diff options
Diffstat (limited to 'buildbot/docs/buildbot.info-1')
-rw-r--r-- | buildbot/docs/buildbot.info-1 | 7278 |
1 files changed, 7278 insertions, 0 deletions
diff --git a/buildbot/docs/buildbot.info-1 b/buildbot/docs/buildbot.info-1 new file mode 100644 index 0000000..5dcf913 --- /dev/null +++ b/buildbot/docs/buildbot.info-1 @@ -0,0 +1,7278 @@ +This is buildbot.info, produced by makeinfo version 4.11 from +buildbot.texinfo. + +This is the BuildBot manual. + + Copyright (C) 2005,2006 Brian Warner + + Copying and distribution of this file, with or without +modification, are permitted in any medium without royalty provided +the copyright notice and this notice are preserved. + + +File: buildbot.info, Node: Top, Next: Introduction, Prev: (dir), Up: (dir) + +BuildBot +******** + +This is the BuildBot manual. + + Copyright (C) 2005,2006 Brian Warner + + Copying and distribution of this file, with or without +modification, are permitted in any medium without royalty provided +the copyright notice and this notice are preserved. + +* Menu: + +* Introduction:: What the BuildBot does. +* Installation:: Creating a buildmaster and buildslaves, + running them. +* Concepts:: What goes on in the buildbot's little mind. +* Configuration:: Controlling the buildbot. +* Getting Source Code Changes:: Discovering when to run a build. +* Build Process:: Controlling how each build is run. +* Status Delivery:: Telling the world about the build's results. +* Command-line tool:: +* Resources:: Getting help. +* Developer's Appendix:: +* Index of Useful Classes:: +* Index of master.cfg keys:: +* Index:: Complete index. + + --- The Detailed Node Listing --- + +Introduction + +* History and Philosophy:: +* System Architecture:: +* Control Flow:: + +System Architecture + +* BuildSlave Connections:: +* Buildmaster Architecture:: +* Status Delivery Architecture:: + +Installation + +* Requirements:: +* Installing the code:: +* Creating a buildmaster:: +* Upgrading an Existing Buildmaster:: +* Creating a buildslave:: +* Launching the daemons:: +* Logfiles:: +* Shutdown:: +* Maintenance:: +* Troubleshooting:: + +Creating a buildslave + +* Buildslave Options:: + +Troubleshooting + +* Starting the buildslave:: +* Connecting to the buildmaster:: +* Forcing Builds:: + +Concepts + +* Version Control Systems:: +* Schedulers:: +* BuildSet:: +* BuildRequest:: +* Builder:: +* Users:: +* Build Properties:: + +Version Control Systems + +* Generalizing VC Systems:: +* Source Tree Specifications:: +* How Different VC Systems Specify Sources:: +* Attributes of Changes:: + +Users + +* Doing Things With Users:: +* Email Addresses:: +* IRC Nicknames:: +* Live Status Clients:: + +Configuration + +* Config File Format:: +* Loading the Config File:: +* Testing the Config File:: +* Defining the Project:: +* Change Sources and Schedulers:: +* Setting the slaveport:: +* Buildslave Specifiers:: +* On-Demand ("Latent") Buildslaves:: +* Defining Global Properties:: +* Defining Builders:: +* Defining Status Targets:: +* Debug options:: + +Change Sources and Schedulers + +* Scheduler Scheduler:: +* AnyBranchScheduler:: +* Dependent Scheduler:: +* Periodic Scheduler:: +* Nightly Scheduler:: +* Try Schedulers:: +* Triggerable Scheduler:: + +Buildslave Specifiers +* When Buildslaves Go Missing:: + +On-Demand ("Latent") Buildslaves +* Amazon Web Services Elastic Compute Cloud ("AWS EC2"):: +* Dangers with Latent Buildslaves:: +* Writing New Latent Buildslaves:: + +Getting Source Code Changes + +* Change Sources:: +* Choosing ChangeSources:: +* CVSToys - PBService:: +* Mail-parsing ChangeSources:: +* PBChangeSource:: +* P4Source:: +* BonsaiPoller:: +* SVNPoller:: +* MercurialHook:: +* Bzr Hook:: +* Bzr Poller:: + +Mail-parsing ChangeSources + +* Subscribing the Buildmaster:: +* Using Maildirs:: +* Parsing Email Change Messages:: + +Parsing Email Change Messages + +* FCMaildirSource:: +* SyncmailMaildirSource:: +* BonsaiMaildirSource:: +* SVNCommitEmailMaildirSource:: + +Build Process + +* Build Steps:: +* Interlocks:: +* Build Factories:: + +Build Steps + +* Common Parameters:: +* Using Build Properties:: +* Source Checkout:: +* ShellCommand:: +* Simple ShellCommand Subclasses:: +* Python BuildSteps:: +* Transferring Files:: +* Steps That Run on the Master:: +* Triggering Schedulers:: +* Writing New BuildSteps:: + +Source Checkout + +* CVS:: +* SVN:: +* Darcs:: +* Mercurial:: +* Arch:: +* Bazaar:: +* Bzr:: +* P4:: +* Git:: + +Simple ShellCommand Subclasses + +* Configure:: +* Compile:: +* Test:: +* TreeSize:: +* PerlModuleTest:: +* SetProperty:: + +Python BuildSteps + +* BuildEPYDoc:: +* PyFlakes:: +* PyLint:: + +Writing New BuildSteps + +* BuildStep LogFiles:: +* Reading Logfiles:: +* Adding LogObservers:: +* BuildStep URLs:: + +Build Factories + +* BuildStep Objects:: +* BuildFactory:: +* Process-Specific build factories:: + +BuildStep Objects + +* BuildFactory Attributes:: +* Quick builds:: + +BuildFactory + +* BuildFactory Attributes:: +* Quick builds:: + +Process-Specific build factories + +* GNUAutoconf:: +* CPAN:: +* Python distutils:: +* Python/Twisted/trial projects:: + +Status Delivery + +* WebStatus:: +* MailNotifier:: +* IRC Bot:: +* PBListener:: +* Writing New Status Plugins:: + +WebStatus + +* WebStatus Configuration Parameters:: +* Buildbot Web Resources:: +* XMLRPC server:: +* HTML Waterfall:: + +Command-line tool + +* Administrator Tools:: +* Developer Tools:: +* Other Tools:: +* .buildbot config directory:: + +Developer Tools + +* statuslog:: +* statusgui:: +* try:: + +waiting for results + +* try --diff:: + +Other Tools + +* sendchange:: +* debugclient:: + + +File: buildbot.info, Node: Introduction, Next: Installation, Prev: Top, Up: Top + +1 Introduction +************** + +The BuildBot is a system to automate the compile/test cycle required +by most software projects to validate code changes. By automatically +rebuilding and testing the tree each time something has changed, +build problems are pinpointed quickly, before other developers are +inconvenienced by the failure. The guilty developer can be identified +and harassed without human intervention. By running the builds on a +variety of platforms, developers who do not have the facilities to +test their changes everywhere before checkin will at least know +shortly afterwards whether they have broken the build or not. Warning +counts, lint checks, image size, compile time, and other build +parameters can be tracked over time, are more visible, and are +therefore easier to improve. + + The overall goal is to reduce tree breakage and provide a platform +to run tests or code-quality checks that are too annoying or pedantic +for any human to waste their time with. Developers get immediate (and +potentially public) feedback about their changes, encouraging them to +be more careful about testing before checkin. + + Features: + + * run builds on a variety of slave platforms + + * arbitrary build process: handles projects using C, Python, + whatever + + * minimal host requirements: python and Twisted + + * slaves can be behind a firewall if they can still do checkout + + * status delivery through web page, email, IRC, other protocols + + * track builds in progress, provide estimated completion time + + * flexible configuration by subclassing generic build process + classes + + * debug tools to force a new build, submit fake Changes, query + slave status + + * released under the GPL + +* Menu: + +* History and Philosophy:: +* System Architecture:: +* Control Flow:: + + +File: buildbot.info, Node: History and Philosophy, Next: System Architecture, Prev: Introduction, Up: Introduction + +1.1 History and Philosophy +========================== + +The Buildbot was inspired by a similar project built for a development +team writing a cross-platform embedded system. The various components +of the project were supposed to compile and run on several flavors of +unix (linux, solaris, BSD), but individual developers had their own +preferences and tended to stick to a single platform. From time to +time, incompatibilities would sneak in (some unix platforms want to +use `string.h', some prefer `strings.h'), and then the tree would +compile for some developers but not others. The buildbot was written +to automate the human process of walking into the office, updating a +tree, compiling (and discovering the breakage), finding the developer +at fault, and complaining to them about the problem they had +introduced. With multiple platforms it was difficult for developers to +do the right thing (compile their potential change on all platforms); +the buildbot offered a way to help. + + Another problem was when programmers would change the behavior of a +library without warning its users, or change internal aspects that +other code was (unfortunately) depending upon. Adding unit tests to +the codebase helps here: if an application's unit tests pass despite +changes in the libraries it uses, you can have more confidence that +the library changes haven't broken anything. Many developers +complained that the unit tests were inconvenient or took too long to +run: having the buildbot run them reduces the developer's workload to +a minimum. + + In general, having more visibility into the project is always good, +and automation makes it easier for developers to do the right thing. +When everyone can see the status of the project, developers are +encouraged to keep the tree in good working order. Unit tests that +aren't run on a regular basis tend to suffer from bitrot just like +code does: exercising them on a regular basis helps to keep them +functioning and useful. + + The current version of the Buildbot is additionally targeted at +distributed free-software projects, where resources and platforms are +only available when provided by interested volunteers. The buildslaves +are designed to require an absolute minimum of configuration, reducing +the effort a potential volunteer needs to expend to be able to +contribute a new test environment to the project. The goal is for +anyone who wishes that a given project would run on their favorite +platform should be able to offer that project a buildslave, running on +that platform, where they can verify that their portability code +works, and keeps working. + + +File: buildbot.info, Node: System Architecture, Next: Control Flow, Prev: History and Philosophy, Up: Introduction + +1.2 System Architecture +======================= + +The Buildbot consists of a single `buildmaster' and one or more +`buildslaves', connected in a star topology. The buildmaster makes +all decisions about what, when, and how to build. It sends commands +to be run on the build slaves, which simply execute the commands and +return the results. (certain steps involve more local decision +making, where the overhead of sending a lot of commands back and +forth would be inappropriate, but in general the buildmaster is +responsible for everything). + + The buildmaster is usually fed `Changes' by some sort of version +control system (*note Change Sources::), which may cause builds to be +run. As the builds are performed, various status messages are +produced, which are then sent to any registered Status Targets (*note +Status Delivery::). + + + +------------------+ +-----------+ + | |---------->| Browser | + | BuildMaster | +-----------+ + Changes | |--------------->+--------+ + +----------->| | Build Status | email | + | | |------------+ +--------+ + | | |-------+ | +---------------+ + | +------------------+ | +---->| Status Client | ++----------+ | ^ | ^ | +---------------+ +| Change | | | C| | | +-----+ +| Sources | | | o| | +------------>| IRC | +| | | | m| |R +-----+ +| CVS | v | m| |e +| SVN | +---------+ a| |s +| Darcs | | Build | n| |u +| .. etc | | Slave | d| |l +| | +---------+ s| |t +| | v |s ++----------+ +---------+ + | Build | + | Slave | + +---------+ + + The buildmaster is configured and maintained by the "buildmaster +admin", who is generally the project team member responsible for +build process issues. Each buildslave is maintained by a "buildslave +admin", who do not need to be quite as involved. Generally slaves are +run by anyone who has an interest in seeing the project work well on +their favorite platform. + +* Menu: + +* BuildSlave Connections:: +* Buildmaster Architecture:: +* Status Delivery Architecture:: + + +File: buildbot.info, Node: BuildSlave Connections, Next: Buildmaster Architecture, Prev: System Architecture, Up: System Architecture + +1.2.1 BuildSlave Connections +---------------------------- + +The buildslaves are typically run on a variety of separate machines, +at least one per platform of interest. These machines connect to the +buildmaster over a TCP connection to a publically-visible port. As a +result, the buildslaves can live behind a NAT box or similar +firewalls, as long as they can get to buildmaster. The TCP connections +are initiated by the buildslave and accepted by the buildmaster, but +commands and results travel both ways within this connection. The +buildmaster is always in charge, so all commands travel exclusively +from the buildmaster to the buildslave. + + To perform builds, the buildslaves must typically obtain source +code from a CVS/SVN/etc repository. Therefore they must also be able +to reach the repository. The buildmaster provides instructions for +performing builds, but does not provide the source code itself. + + + +Repository| | BuildMaster | | + (CVS/SVN)| | ^|^^^ | + | | / c \ | +----------+ +------------------/--o----\-+ + ^ / m ^ \ + | / m | \ + checkout/update --+ a | +-- + | TCP| n | |TCP + | | d | | + | | s | | + | | | | | + | | | r | + | | | e | + -N-A-T-|- - - - -N-A-T- - - - -|- |- s-|- - - - -N-A-T- - - + | | | u | + | | | l | + | +------------------|--|--t-|-+ + | | | | s | | + +----| v | | + | | | + | | | + | | + | BuildSlave | + +----------------------------+ + + +File: buildbot.info, Node: Buildmaster Architecture, Next: Status Delivery Architecture, Prev: BuildSlave Connections, Up: System Architecture + +1.2.2 Buildmaster Architecture +------------------------------ + +The Buildmaster consists of several pieces: + + + + +---------------+ + | Change Source |----->----+ + +---------------+ | + Changes + | + +---------------+ v + | Change Source |----->----+ + +---------------+ v + +-----+-------+ + | | + v v + +-----------+ +-----------+ + | Scheduler | | Scheduler | + +-----------+ +-----------+ + | | | + +------+---------+ +---+ +-----+ + | | | | + v | | Build + : : : v v : Request + : : : : | + : ---- : : : | + : ---- : : ---- : | + +======+ +======+ : v : + | | : : + v v : : + +---------+ +---------+ :queue : + | Builder | | Builder | +======+ + +---------+ +---------+ | + v + +---------+ + | Builder | + +---------+ + + * Change Sources, which create a Change object each time something + is modified in the VC repository. Most ChangeSources listen for + messages from a hook script of some sort. Some sources actively + poll the repository on a regular basis. All Changes are fed to + the Schedulers. + + * Schedulers, which decide when builds should be performed. They + collect Changes into BuildRequests, which are then queued for + delivery to Builders until a buildslave is available. + + * Builders, which control exactly _how_ each build is performed + (with a series of BuildSteps, configured in a BuildFactory). Each + Build is run on a single buildslave. + + * Status plugins, which deliver information about the build results + through protocols like HTTP, mail, and IRC. + + + + + +-----------------+ + | BuildSlave | + | | + | | + +-------+ | +------------+ | + |Builder|----Build----->|SlaveBuilder| | + +-------+ | +------------+ | + | | + | +------------+ | + +-Build---->|SlaveBuilder| | + | | +------------+ | + +-------+ | | | + |Builder|---+ +-----------------+ + +-------+ | + | + | +-----------------+ + Build | BuildSlave | + | | | + | | | + | | +------------+ | + +------->|SlaveBuilder| | + | +------------+ | + +-------+ | | + |Builder|--+ | +------------+ | + +-------+ +-------->|SlaveBuilder| | + | +------------+ | + | | + +-----------------+ + + Each Builder is configured with a list of BuildSlaves that it will +use for its builds. These buildslaves are expected to behave +identically: the only reason to use multiple BuildSlaves for a single +Builder is to provide a measure of load-balancing. + + Within a single BuildSlave, each Builder creates its own +SlaveBuilder instance. These SlaveBuilders operate independently from +each other. Each gets its own base directory to work in. It is quite +common to have many Builders sharing the same buildslave. For +example, there might be two buildslaves: one for i386, and a second +for PowerPC. There may then be a pair of Builders that do a full +compile/test run, one for each architecture, and a lone Builder that +creates snapshot source tarballs if the full builders complete +successfully. The full builders would each run on a single +buildslave, whereas the tarball creation step might run on either +buildslave (since the platform doesn't matter when creating source +tarballs). In this case, the mapping would look like: + + Builder(full-i386) -> BuildSlaves(slave-i386) + Builder(full-ppc) -> BuildSlaves(slave-ppc) + Builder(source-tarball) -> BuildSlaves(slave-i386, slave-ppc) + + and each BuildSlave would have two SlaveBuilders inside it, one +for a full builder, and a second for the source-tarball builder. + + Once a SlaveBuilder is available, the Builder pulls one or more +BuildRequests off its incoming queue. (It may pull more than one if it +determines that it can merge the requests together; for example, there +may be multiple requests to build the current HEAD revision). These +requests are merged into a single Build instance, which includes the +SourceStamp that describes what exact version of the source code +should be used for the build. The Build is then randomly assigned to a +free SlaveBuilder and the build begins. + + The behaviour when BuildRequests are merged can be customized, +*note Merging BuildRequests::. + + +File: buildbot.info, Node: Status Delivery Architecture, Prev: Buildmaster Architecture, Up: System Architecture + +1.2.3 Status Delivery Architecture +---------------------------------- + +The buildmaster maintains a central Status object, to which various +status plugins are connected. Through this Status object, a full +hierarchy of build status objects can be obtained. + + + + Status Objects Status Plugins User Clients + + +------+ +---------+ +-----------+ + |Status|<--------------+-->|Waterfall|<-------|Web Browser| + +------+ | +---------+ +-----------+ + | +-----+ | + v v | ++-------+ +-------+ | +---+ +----------+ +|Builder| |Builder| +---->|IRC|<----------->IRC Server| +|Status | |Status | | +---+ +----------+ ++-------+ +-------+ | + | +----+ | + v v | +------------+ +----+ ++------+ +------+ +-->|MailNotifier|---->|SMTP| +|Build | |Build | +------------+ +----+ +|Status| |Status| ++------+ +------+ + | +-----+ + v v ++------+ +------+ +|Step | |Step | +|Status| |Status| ++------+ +------+ + | +---+ + v v ++----+ +----+ +|Log | |Log | +|File| |File| ++----+ +----+ + + The configuration file controls which status plugins are active. +Each status plugin gets a reference to the top-level Status object. +From there they can request information on each Builder, Build, Step, +and LogFile. This query-on-demand interface is used by the +html.Waterfall plugin to create the main status page each time a web +browser hits the main URL. + + The status plugins can also subscribe to hear about new Builds as +they occur: this is used by the MailNotifier to create new email +messages for each recently-completed Build. + + The Status object records the status of old builds on disk in the +buildmaster's base directory. This allows it to return information +about historical builds. + + There are also status objects that correspond to Schedulers and +BuildSlaves. These allow status plugins to report information about +upcoming builds, and the online/offline status of each buildslave. + + +File: buildbot.info, Node: Control Flow, Prev: System Architecture, Up: Introduction + +1.3 Control Flow +================ + +A day in the life of the buildbot: + + * A developer commits some source code changes to the repository. + A hook script or commit trigger of some sort sends information + about this change to the buildmaster through one of its + configured Change Sources. This notification might arrive via + email, or over a network connection (either initiated by the + buildmaster as it "subscribes" to changes, or by the commit + trigger as it pushes Changes towards the buildmaster). The + Change contains information about who made the change, what + files were modified, which revision contains the change, and any + checkin comments. + + * The buildmaster distributes this change to all of its configured + Schedulers. Any "important" changes cause the "tree-stable-timer" + to be started, and the Change is added to a list of those that + will go into a new Build. When the timer expires, a Build is + started on each of a set of configured Builders, all + compiling/testing the same source code. Unless configured + otherwise, all Builds run in parallel on the various buildslaves. + + * The Build consists of a series of Steps. Each Step causes some + number of commands to be invoked on the remote buildslave + associated with that Builder. The first step is almost always to + perform a checkout of the appropriate revision from the same VC + system that produced the Change. The rest generally perform a + compile and run unit tests. As each Step runs, the buildslave + reports back command output and return status to the buildmaster. + + * As the Build runs, status messages like "Build Started", "Step + Started", "Build Finished", etc, are published to a collection of + Status Targets. One of these targets is usually the HTML + "Waterfall" display, which shows a chronological list of events, + and summarizes the results of the most recent build at the top + of each column. Developers can periodically check this page to + see how their changes have fared. If they see red, they know + that they've made a mistake and need to fix it. If they see + green, they know that they've done their duty and don't need to + worry about their change breaking anything. + + * If a MailNotifier status target is active, the completion of a + build will cause email to be sent to any developers whose + Changes were incorporated into this Build. The MailNotifier can + be configured to only send mail upon failing builds, or for + builds which have just transitioned from passing to failing. + Other status targets can provide similar real-time notification + via different communication channels, like IRC. + + + +File: buildbot.info, Node: Installation, Next: Concepts, Prev: Introduction, Up: Top + +2 Installation +************** + +* Menu: + +* Requirements:: +* Installing the code:: +* Creating a buildmaster:: +* Upgrading an Existing Buildmaster:: +* Creating a buildslave:: +* Launching the daemons:: +* Logfiles:: +* Shutdown:: +* Maintenance:: +* Troubleshooting:: + + +File: buildbot.info, Node: Requirements, Next: Installing the code, Prev: Installation, Up: Installation + +2.1 Requirements +================ + +At a bare minimum, you'll need the following (for both the buildmaster +and a buildslave): + + * Python: http://www.python.org + + Buildbot requires python-2.3 or later, and is primarily developed + against python-2.4. It is also tested against python-2.5 . + + * Twisted: http://twistedmatrix.com + + Both the buildmaster and the buildslaves require Twisted-2.0.x or + later. It has been tested against all releases of Twisted up to + Twisted-2.5.0 (the most recent as of this writing). As always, + the most recent version is recommended. + + Twisted is delivered as a collection of subpackages. You'll need + at least "Twisted" (the core package), and you'll also want + TwistedMail, TwistedWeb, and TwistedWords (for sending email, + serving a web status page, and delivering build status via IRC, + respectively). You might also want TwistedConch (for the + encrypted Manhole debug port). Note that Twisted requires + ZopeInterface to be installed as well. + + + Certain other packages may be useful on the system running the +buildmaster: + + * CVSToys: http://purl.net/net/CVSToys + + If your buildmaster uses FreshCVSSource to receive change + notification from a cvstoys daemon, it will require CVSToys be + installed (tested with CVSToys-1.0.10). If the it doesn't use + that source (i.e. if you only use a mail-parsing change source, + or the SVN notification script), you will not need CVSToys. + + + And of course, your project's build process will impose additional +requirements on the buildslaves. These hosts must have all the tools +necessary to compile and test your project's source code. + + +File: buildbot.info, Node: Installing the code, Next: Creating a buildmaster, Prev: Requirements, Up: Installation + +2.2 Installing the code +======================= + +The Buildbot is installed using the standard python `distutils' +module. After unpacking the tarball, the process is: + + python setup.py build + python setup.py install + + where the install step may need to be done as root. This will put +the bulk of the code in somewhere like +/usr/lib/python2.3/site-packages/buildbot . It will also install the +`buildbot' command-line tool in /usr/bin/buildbot. + + To test this, shift to a different directory (like /tmp), and run: + + buildbot --version + + If it shows you the versions of Buildbot and Twisted, the install +went ok. If it says `no such command' or it gets an `ImportError' +when it tries to load the libaries, then something went wrong. +`pydoc buildbot' is another useful diagnostic tool. + + Windows users will find these files in other places. You will need +to make sure that python can find the libraries, and will probably +find it convenient to have `buildbot' on your PATH. + + If you wish, you can run the buildbot unit test suite like this: + + PYTHONPATH=. trial buildbot.test + + This should run up to 192 tests, depending upon what VC tools you +have installed. On my desktop machine it takes about five minutes to +complete. Nothing should fail, a few might be skipped. If any of the +tests fail, you should stop and investigate the cause before +continuing the installation process, as it will probably be easier to +track down the bug early. + + If you cannot or do not wish to install the buildbot into a +site-wide location like `/usr' or `/usr/local', you can also install +it into the account's home directory. Do the install command like +this: + + python setup.py install --home=~ + + That will populate `~/lib/python' and create `~/bin/buildbot'. +Make sure this lib directory is on your `PYTHONPATH'. + + +File: buildbot.info, Node: Creating a buildmaster, Next: Upgrading an Existing Buildmaster, Prev: Installing the code, Up: Installation + +2.3 Creating a buildmaster +========================== + +As you learned earlier (*note System Architecture::), the buildmaster +runs on a central host (usually one that is publically visible, so +everybody can check on the status of the project), and controls all +aspects of the buildbot system. Let us call this host +`buildbot.example.org'. + + You may wish to create a separate user account for the buildmaster, +perhaps named `buildmaster'. This can help keep your personal +configuration distinct from that of the buildmaster and is useful if +you have to use a mail-based notification system (*note Change +Sources::). However, the Buildbot will work just fine with your +regular user account. + + You need to choose a directory for the buildmaster, called the +`basedir'. This directory will be owned by the buildmaster, which +will use configuration files therein, and create status files as it +runs. `~/Buildbot' is a likely value. If you run multiple +buildmasters in the same account, or if you run both masters and +slaves, you may want a more distinctive name like +`~/Buildbot/master/gnomovision' or `~/Buildmasters/fooproject'. If +you are using a separate user account, this might just be +`~buildmaster/masters/fooproject'. + + Once you've picked a directory, use the `buildbot create-master' +command to create the directory and populate it with startup files: + + buildbot create-master BASEDIR + + You will need to create a configuration file (*note +Configuration::) before starting the buildmaster. Most of the rest of +this manual is dedicated to explaining how to do this. A sample +configuration file is placed in the working directory, named +`master.cfg.sample', which can be copied to `master.cfg' and edited +to suit your purposes. + + (Internal details: This command creates a file named +`buildbot.tac' that contains all the state necessary to create the +buildmaster. Twisted has a tool called `twistd' which can use this +.tac file to create and launch a buildmaster instance. twistd takes +care of logging and daemonization (running the program in the +background). `/usr/bin/buildbot' is a front end which runs twistd for +you.) + + In addition to `buildbot.tac', a small `Makefile.sample' is +installed. This can be used as the basis for customized daemon +startup, *Note Launching the daemons::. + + +File: buildbot.info, Node: Upgrading an Existing Buildmaster, Next: Creating a buildslave, Prev: Creating a buildmaster, Up: Installation + +2.4 Upgrading an Existing Buildmaster +===================================== + +If you have just installed a new version of the Buildbot code, and you +have buildmasters that were created using an older version, you'll +need to upgrade these buildmasters before you can use them. The +upgrade process adds and modifies files in the buildmaster's base +directory to make it compatible with the new code. + + buildbot upgrade-master BASEDIR + + This command will also scan your `master.cfg' file for +incompatbilities (by loading it and printing any errors or deprecation +warnings that occur). Each buildbot release tries to be compatible +with configurations that worked cleanly (i.e. without deprecation +warnings) on the previous release: any functions or classes that are +to be removed will first be deprecated in a release, to give users a +chance to start using their replacement. + + The 0.7.6 release introduced the `public_html/' directory, which +contains `index.html' and other files served by the `WebStatus' and +`Waterfall' status displays. The `upgrade-master' command will create +these files if they do not already exist. It will not modify existing +copies, but it will write a new copy in e.g. `index.html.new' if the +new version differs from the version that already exists. + + The `upgrade-master' command is idempotent. It is safe to run it +multiple times. After each upgrade of the buildbot code, you should +use `upgrade-master' on all your buildmasters. + + +File: buildbot.info, Node: Creating a buildslave, Next: Launching the daemons, Prev: Upgrading an Existing Buildmaster, Up: Installation + +2.5 Creating a buildslave +========================= + +Typically, you will be adding a buildslave to an existing buildmaster, +to provide additional architecture coverage. The buildbot +administrator will give you several pieces of information necessary to +connect to the buildmaster. You should also be somewhat familiar with +the project being tested, so you can troubleshoot build problems +locally. + + The buildbot exists to make sure that the project's stated "how to +build it" process actually works. To this end, the buildslave should +run in an environment just like that of your regular developers. +Typically the project build process is documented somewhere +(`README', `INSTALL', etc), in a document that should mention all +library dependencies and contain a basic set of build instructions. +This document will be useful as you configure the host and account in +which the buildslave runs. + + Here's a good checklist for setting up a buildslave: + + 1. Set up the account + + It is recommended (although not mandatory) to set up a separate + user account for the buildslave. This account is frequently named + `buildbot' or `buildslave'. This serves to isolate your personal + working environment from that of the slave's, and helps to + minimize the security threat posed by letting possibly-unknown + contributors run arbitrary code on your system. The account + should have a minimum of fancy init scripts. + + 2. Install the buildbot code + + Follow the instructions given earlier (*note Installing the + code::). If you use a separate buildslave account, and you + didn't install the buildbot code to a shared location, then you + will need to install it with `--home=~' for each account that + needs it. + + 3. Set up the host + + Make sure the host can actually reach the buildmaster. Usually + the buildmaster is running a status webserver on the same + machine, so simply point your web browser at it and see if you + can get there. Install whatever additional packages or + libraries the project's INSTALL document advises. (or not: if + your buildslave is supposed to make sure that building without + optional libraries still works, then don't install those + libraries). + + Again, these libraries don't necessarily have to be installed to + a site-wide shared location, but they must be available to your + build process. Accomplishing this is usually very specific to + the build process, so installing them to `/usr' or `/usr/local' + is usually the best approach. + + 4. Test the build process + + Follow the instructions in the INSTALL document, in the + buildslave's account. Perform a full CVS (or whatever) checkout, + configure, make, run tests, etc. Confirm that the build works + without manual fussing. If it doesn't work when you do it by + hand, it will be unlikely to work when the buildbot attempts to + do it in an automated fashion. + + 5. Choose a base directory + + This should be somewhere in the buildslave's account, typically + named after the project which is being tested. The buildslave + will not touch any file outside of this directory. Something + like `~/Buildbot' or `~/Buildslaves/fooproject' is appropriate. + + 6. Get the buildmaster host/port, botname, and password + + When the buildbot admin configures the buildmaster to accept and + use your buildslave, they will provide you with the following + pieces of information: + + * your buildslave's name + + * the password assigned to your buildslave + + * the hostname and port number of the buildmaster, i.e. + buildbot.example.org:8007 + + 7. Create the buildslave + + Now run the 'buildbot' command as follows: + + buildbot create-slave BASEDIR MASTERHOST:PORT SLAVENAME PASSWORD + + This will create the base directory and a collection of files + inside, including the `buildbot.tac' file that contains all the + information you passed to the `buildbot' command. + + 8. Fill in the hostinfo files + + When it first connects, the buildslave will send a few files up + to the buildmaster which describe the host that it is running + on. These files are presented on the web status display so that + developers have more information to reproduce any test failures + that are witnessed by the buildbot. There are sample files in + the `info' subdirectory of the buildbot's base directory. You + should edit these to correctly describe you and your host. + + `BASEDIR/info/admin' should contain your name and email address. + This is the "buildslave admin address", and will be visible from + the build status page (so you may wish to munge it a bit if + address-harvesting spambots are a concern). + + `BASEDIR/info/host' should be filled with a brief description of + the host: OS, version, memory size, CPU speed, versions of + relevant libraries installed, and finally the version of the + buildbot code which is running the buildslave. + + If you run many buildslaves, you may want to create a single + `~buildslave/info' file and share it among all the buildslaves + with symlinks. + + +* Menu: + +* Buildslave Options:: + + +File: buildbot.info, Node: Buildslave Options, Prev: Creating a buildslave, Up: Creating a buildslave + +2.5.1 Buildslave Options +------------------------ + +There are a handful of options you might want to use when creating the +buildslave with the `buildbot create-slave <options> DIR <params>' +command. You can type `buildbot create-slave --help' for a summary. +To use these, just include them on the `buildbot create-slave' +command line, like this: + + buildbot create-slave --umask=022 ~/buildslave buildmaster.example.org:42012 myslavename mypasswd + +`--usepty' + This is a boolean flag that tells the buildslave whether to + launch child processes in a PTY or with regular pipes (the + default) when the master does not specify. This option is + deprecated, as this particular parameter is better specified on + the master. + +`--umask' + This is a string (generally an octal representation of an + integer) which will cause the buildslave process' "umask" value + to be set shortly after initialization. The "twistd" + daemonization utility forces the umask to 077 at startup (which + means that all files created by the buildslave or its child + processes will be unreadable by any user other than the + buildslave account). If you want build products to be readable + by other accounts, you can add `--umask=022' to tell the + buildslave to fix the umask after twistd clobbers it. If you want + build products to be _writable_ by other accounts too, use + `--umask=000', but this is likely to be a security problem. + +`--keepalive' + This is a number that indicates how frequently "keepalive" + messages should be sent from the buildslave to the buildmaster, + expressed in seconds. The default (600) causes a message to be + sent to the buildmaster at least once every 10 minutes. To set + this to a lower value, use e.g. `--keepalive=120'. + + If the buildslave is behind a NAT box or stateful firewall, these + messages may help to keep the connection alive: some NAT boxes + tend to forget about a connection if it has not been used in a + while. When this happens, the buildmaster will think that the + buildslave has disappeared, and builds will time out. Meanwhile + the buildslave will not realize than anything is wrong. + +`--maxdelay' + This is a number that indicates the maximum amount of time the + buildslave will wait between connection attempts, expressed in + seconds. The default (300) causes the buildslave to wait at most + 5 minutes before trying to connect to the buildmaster again. + +`--log-size' + This is the size in bytes when to rotate the Twisted log files. + +`--log-count' + This is the number of log rotations to keep around. You can + either specify a number or `None' (the default) to keep all + `twistd.log' files around. + + + +File: buildbot.info, Node: Launching the daemons, Next: Logfiles, Prev: Creating a buildslave, Up: Installation + +2.6 Launching the daemons +========================= + +Both the buildmaster and the buildslave run as daemon programs. To +launch them, pass the working directory to the `buildbot' command: + + buildbot start BASEDIR + + This command will start the daemon and then return, so normally it +will not produce any output. To verify that the programs are indeed +running, look for a pair of files named `twistd.log' and `twistd.pid' +that should be created in the working directory. `twistd.pid' +contains the process ID of the newly-spawned daemon. + + When the buildslave connects to the buildmaster, new directories +will start appearing in its base directory. The buildmaster tells the +slave to create a directory for each Builder which will be using that +slave. All build operations are performed within these directories: +CVS checkouts, compiles, and tests. + + Once you get everything running, you will want to arrange for the +buildbot daemons to be started at boot time. One way is to use +`cron', by putting them in a @reboot crontab entry(1): + + @reboot buildbot start BASEDIR + + When you run `crontab' to set this up, remember to do it as the +buildmaster or buildslave account! If you add this to your crontab +when running as your regular account (or worse yet, root), then the +daemon will run as the wrong user, quite possibly as one with more +authority than you intended to provide. + + It is important to remember that the environment provided to cron +jobs and init scripts can be quite different that your normal runtime. +There may be fewer environment variables specified, and the PATH may +be shorter than usual. It is a good idea to test out this method of +launching the buildslave by using a cron job with a time in the near +future, with the same command, and then check `twistd.log' to make +sure the slave actually started correctly. Common problems here are +for `/usr/local' or `~/bin' to not be on your `PATH', or for +`PYTHONPATH' to not be set correctly. Sometimes `HOME' is messed up +too. + + To modify the way the daemons are started (perhaps you want to set +some environment variables first, or perform some cleanup each time), +you can create a file named `Makefile.buildbot' in the base +directory. When the `buildbot' front-end tool is told to `start' the +daemon, and it sees this file (and `/usr/bin/make' exists), it will +do `make -f Makefile.buildbot start' instead of its usual action +(which involves running `twistd'). When the buildmaster or buildslave +is installed, a `Makefile.sample' is created which implements the +same behavior as the the `buildbot' tool uses, so if you want to +customize the process, just copy `Makefile.sample' to +`Makefile.buildbot' and edit it as necessary. + + Some distributions may include conveniences to make starting +buildbot at boot time easy. For instance, with the default buildbot +package in Debian-based distributions, you may only need to modify +`/etc/default/buildbot' (see also `/etc/init.d/buildbot', which reads +the configuration in `/etc/default/buildbot'). + + ---------- Footnotes ---------- + + (1) this @reboot syntax is understood by Vixie cron, which is the +flavor usually provided with linux systems. Other unices may have a +cron that doesn't understand @reboot + + +File: buildbot.info, Node: Logfiles, Next: Shutdown, Prev: Launching the daemons, Up: Installation + +2.7 Logfiles +============ + +While a buildbot daemon runs, it emits text to a logfile, named +`twistd.log'. A command like `tail -f twistd.log' is useful to watch +the command output as it runs. + + The buildmaster will announce any errors with its configuration +file in the logfile, so it is a good idea to look at the log at +startup time to check for any problems. Most buildmaster activities +will cause lines to be added to the log. + + +File: buildbot.info, Node: Shutdown, Next: Maintenance, Prev: Logfiles, Up: Installation + +2.8 Shutdown +============ + +To stop a buildmaster or buildslave manually, use: + + buildbot stop BASEDIR + + This simply looks for the `twistd.pid' file and kills whatever +process is identified within. + + At system shutdown, all processes are sent a `SIGKILL'. The +buildmaster and buildslave will respond to this by shutting down +normally. + + The buildmaster will respond to a `SIGHUP' by re-reading its +config file. Of course, this only works on unix-like systems with +signal support, and won't work on Windows. The following shortcut is +available: + + buildbot reconfig BASEDIR + + When you update the Buildbot code to a new release, you will need +to restart the buildmaster and/or buildslave before it can take +advantage of the new code. You can do a `buildbot stop BASEDIR' and +`buildbot start BASEDIR' in quick succession, or you can use the +`restart' shortcut, which does both steps for you: + + buildbot restart BASEDIR + + There are certain configuration changes that are not handled +cleanly by `buildbot reconfig'. If this occurs, `buildbot restart' is +a more robust tool to fully switch over to the new configuration. + + `buildbot restart' may also be used to start a stopped Buildbot +instance. This behaviour is useful when writing scripts that stop, +start and restart Buildbot. + + A buildslave may also be gracefully shutdown from the *note +WebStatus:: status plugin. This is useful to shutdown a buildslave +without interrupting any current builds. The buildmaster will wait +until the buildslave is finished all its current builds, and will +then tell the buildslave to shutdown. + + +File: buildbot.info, Node: Maintenance, Next: Troubleshooting, Prev: Shutdown, Up: Installation + +2.9 Maintenance +=============== + +It is a good idea to check the buildmaster's status page every once in +a while, to see if your buildslave is still online. Eventually the +buildbot will probably be enhanced to send you email (via the +`info/admin' email address) when the slave has been offline for more +than a few hours. + + If you find you can no longer provide a buildslave to the project, +please let the project admins know, so they can put out a call for a +replacement. + + The Buildbot records status and logs output continually, each time +a build is performed. The status tends to be small, but the build logs +can become quite large. Each build and log are recorded in a separate +file, arranged hierarchically under the buildmaster's base directory. +To prevent these files from growing without bound, you should +periodically delete old build logs. A simple cron job to delete +anything older than, say, two weeks should do the job. The only trick +is to leave the `buildbot.tac' and other support files alone, for +which find's `-mindepth' argument helps skip everything in the top +directory. You can use something like the following: + + @weekly cd BASEDIR && find . -mindepth 2 i-path './public_html/*' -prune -o -type f -mtime +14 -exec rm {} \; + @weekly cd BASEDIR && find twistd.log* -mtime +14 -exec rm {} \; + + +File: buildbot.info, Node: Troubleshooting, Prev: Maintenance, Up: Installation + +2.10 Troubleshooting +==================== + +Here are a few hints on diagnosing common problems. + +* Menu: + +* Starting the buildslave:: +* Connecting to the buildmaster:: +* Forcing Builds:: + + +File: buildbot.info, Node: Starting the buildslave, Next: Connecting to the buildmaster, Prev: Troubleshooting, Up: Troubleshooting + +2.10.1 Starting the buildslave +------------------------------ + +Cron jobs are typically run with a minimal shell (`/bin/sh', not +`/bin/bash'), and tilde expansion is not always performed in such +commands. You may want to use explicit paths, because the `PATH' is +usually quite short and doesn't include anything set by your shell's +startup scripts (`.profile', `.bashrc', etc). If you've installed +buildbot (or other python libraries) to an unusual location, you may +need to add a `PYTHONPATH' specification (note that python will do +tilde-expansion on `PYTHONPATH' elements by itself). Sometimes it is +safer to fully-specify everything: + + @reboot PYTHONPATH=~/lib/python /usr/local/bin/buildbot start /usr/home/buildbot/basedir + + Take the time to get the @reboot job set up. Otherwise, things +will work fine for a while, but the first power outage or system +reboot you have will stop the buildslave with nothing but the cries +of sorrowful developers to remind you that it has gone away. + + +File: buildbot.info, Node: Connecting to the buildmaster, Next: Forcing Builds, Prev: Starting the buildslave, Up: Troubleshooting + +2.10.2 Connecting to the buildmaster +------------------------------------ + +If the buildslave cannot connect to the buildmaster, the reason should +be described in the `twistd.log' logfile. Some common problems are an +incorrect master hostname or port number, or a mistyped bot name or +password. If the buildslave loses the connection to the master, it is +supposed to attempt to reconnect with an exponentially-increasing +backoff. Each attempt (and the time of the next attempt) will be +logged. If you get impatient, just manually stop and re-start the +buildslave. + + When the buildmaster is restarted, all slaves will be disconnected, +and will attempt to reconnect as usual. The reconnect time will depend +upon how long the buildmaster is offline (i.e. how far up the +exponential backoff curve the slaves have travelled). Again, +`buildbot stop BASEDIR; buildbot start BASEDIR' will speed up the +process. + + +File: buildbot.info, Node: Forcing Builds, Prev: Connecting to the buildmaster, Up: Troubleshooting + +2.10.3 Forcing Builds +--------------------- + +From the buildmaster's main status web page, you can force a build to +be run on your build slave. Figure out which column is for a builder +that runs on your slave, click on that builder's name, and the page +that comes up will have a "Force Build" button. Fill in the form, hit +the button, and a moment later you should see your slave's +`twistd.log' filling with commands being run. Using `pstree' or `top' +should also reveal the cvs/make/gcc/etc processes being run by the +buildslave. Note that the same web page should also show the `admin' +and `host' information files that you configured earlier. + + +File: buildbot.info, Node: Concepts, Next: Configuration, Prev: Installation, Up: Top + +3 Concepts +********** + +This chapter defines some of the basic concepts that the Buildbot +uses. You'll need to understand how the Buildbot sees the world to +configure it properly. + +* Menu: + +* Version Control Systems:: +* Schedulers:: +* BuildSet:: +* BuildRequest:: +* Builder:: +* Users:: +* Build Properties:: + + +File: buildbot.info, Node: Version Control Systems, Next: Schedulers, Prev: Concepts, Up: Concepts + +3.1 Version Control Systems +=========================== + +These source trees come from a Version Control System of some kind. +CVS and Subversion are two popular ones, but the Buildbot supports +others. All VC systems have some notion of an upstream `repository' +which acts as a server(1), from which clients can obtain source trees +according to various parameters. The VC repository provides source +trees of various projects, for different branches, and from various +points in time. The first thing we have to do is to specify which +source tree we want to get. + +* Menu: + +* Generalizing VC Systems:: +* Source Tree Specifications:: +* How Different VC Systems Specify Sources:: +* Attributes of Changes:: + + ---------- Footnotes ---------- + + (1) except Darcs, but since the Buildbot never modifies its local +source tree we can ignore the fact that Darcs uses a less centralized +model + + +File: buildbot.info, Node: Generalizing VC Systems, Next: Source Tree Specifications, Prev: Version Control Systems, Up: Version Control Systems + +3.1.1 Generalizing VC Systems +----------------------------- + +For the purposes of the Buildbot, we will try to generalize all VC +systems as having repositories that each provide sources for a variety +of projects. Each project is defined as a directory tree with source +files. The individual files may each have revisions, but we ignore +that and treat the project as a whole as having a set of revisions +(CVS is really the only VC system still in widespread use that has +per-file revisions.. everything modern has moved to atomic tree-wide +changesets). Each time someone commits a change to the project, a new +revision becomes available. These revisions can be described by a +tuple with two items: the first is a branch tag, and the second is +some kind of revision stamp or timestamp. Complex projects may have +multiple branch tags, but there is always a default branch. The +timestamp may be an actual timestamp (such as the -D option to CVS), +or it may be a monotonically-increasing transaction number (such as +the change number used by SVN and P4, or the revision number used by +Arch/Baz/Bazaar, or a labeled tag used in CVS)(1). The SHA1 revision +ID used by Monotone, Mercurial, and Git is also a kind of revision +stamp, in that it specifies a unique copy of the source tree, as does +a Darcs "context" file. + + When we aren't intending to make any changes to the sources we +check out (at least not any that need to be committed back upstream), +there are two basic ways to use a VC system: + + * Retrieve a specific set of source revisions: some tag or key is + used to index this set, which is fixed and cannot be changed by + subsequent developers committing new changes to the tree. + Releases are built from tagged revisions like this, so that they + can be rebuilt again later (probably with controlled + modifications). + + * Retrieve the latest sources along a specific branch: some tag is + used to indicate which branch is to be used, but within that + constraint we want to get the latest revisions. + + Build personnel or CM staff typically use the first approach: the +build that results is (ideally) completely specified by the two +parameters given to the VC system: repository and revision tag. This +gives QA and end-users something concrete to point at when reporting +bugs. Release engineers are also reportedly fond of shipping code that +can be traced back to a concise revision tag of some sort. + + Developers are more likely to use the second approach: each morning +the developer does an update to pull in the changes committed by the +team over the last day. These builds are not easy to fully specify: it +depends upon exactly when you did a checkout, and upon what local +changes the developer has in their tree. Developers do not normally +tag each build they produce, because there is usually significant +overhead involved in creating these tags. Recreating the trees used by +one of these builds can be a challenge. Some VC systems may provide +implicit tags (like a revision number), while others may allow the use +of timestamps to mean "the state of the tree at time X" as opposed to +a tree-state that has been explicitly marked. + + The Buildbot is designed to help developers, so it usually works in +terms of _the latest_ sources as opposed to specific tagged +revisions. However, it would really prefer to build from reproducible +source trees, so implicit revisions are used whenever possible. + + ---------- Footnotes ---------- + + (1) many VC systems provide more complexity than this: in +particular the local views that P4 and ClearCase can assemble out of +various source directories are more complex than we're prepared to +take advantage of here + + +File: buildbot.info, Node: Source Tree Specifications, Next: How Different VC Systems Specify Sources, Prev: Generalizing VC Systems, Up: Version Control Systems + +3.1.2 Source Tree Specifications +-------------------------------- + +So for the Buildbot's purposes we treat each VC system as a server +which can take a list of specifications as input and produce a source +tree as output. Some of these specifications are static: they are +attributes of the builder and do not change over time. Others are more +variable: each build will have a different value. The repository is +changed over time by a sequence of Changes, each of which represents a +single developer making changes to some set of files. These Changes +are cumulative(1). + + For normal builds, the Buildbot wants to get well-defined source +trees that contain specific Changes, and exclude other Changes that +may have occurred after the desired ones. We assume that the Changes +arrive at the buildbot (through one of the mechanisms described in +*note Change Sources::) in the same order in which they are committed +to the repository. The Buildbot waits for the tree to become "stable" +before initiating a build, for two reasons. The first is that +developers frequently make multiple related commits in quick +succession, even when the VC system provides ways to make atomic +transactions involving multiple files at the same time. Running a +build in the middle of these sets of changes would use an inconsistent +set of source files, and is likely to fail (and is certain to be less +useful than a build which uses the full set of changes). The +tree-stable-timer is intended to avoid these useless builds that +include some of the developer's changes but not all. The second reason +is that some VC systems (i.e. CVS) do not provide repository-wide +transaction numbers, so that timestamps are the only way to refer to +a specific repository state. These timestamps may be somewhat +ambiguous, due to processing and notification delays. By waiting until +the tree has been stable for, say, 10 minutes, we can choose a +timestamp from the middle of that period to use for our source +checkout, and then be reasonably sure that any clock-skew errors will +not cause the build to be performed on an inconsistent set of source +files. + + The Schedulers always use the tree-stable-timer, with a timeout +that is configured to reflect a reasonable tradeoff between build +latency and change frequency. When the VC system provides coherent +repository-wide revision markers (such as Subversion's revision +numbers, or in fact anything other than CVS's timestamps), the +resulting Build is simply performed against a source tree defined by +that revision marker. When the VC system does not provide this, a +timestamp from the middle of the tree-stable period is used to +generate the source tree(2). + + ---------- Footnotes ---------- + + (1) Monotone's _multiple heads_ feature violates this assumption +of cumulative Changes, but in most situations the changes don't occur +frequently enough for this to be a significant problem + + (2) this `checkoutDelay' defaults to half the tree-stable timer, +but it can be overridden with an argument to the Source Step + + +File: buildbot.info, Node: How Different VC Systems Specify Sources, Next: Attributes of Changes, Prev: Source Tree Specifications, Up: Version Control Systems + +3.1.3 How Different VC Systems Specify Sources +---------------------------------------------- + +For CVS, the static specifications are `repository' and `module'. In +addition to those, each build uses a timestamp (or omits the +timestamp to mean `the latest') and `branch tag' (which defaults to +HEAD). These parameters collectively specify a set of sources from +which a build may be performed. + + Subversion (http://subversion.tigris.org) combines the repository, +module, and branch into a single `Subversion URL' parameter. Within +that scope, source checkouts can be specified by a numeric `revision +number' (a repository-wide monotonically-increasing marker, such that +each transaction that changes the repository is indexed by a +different revision number), or a revision timestamp. When branches +are used, the repository and module form a static `baseURL', while +each build has a `revision number' and a `branch' (which defaults to a +statically-specified `defaultBranch'). The `baseURL' and `branch' are +simply concatenated together to derive the `svnurl' to use for the +checkout. + + Perforce (http://www.perforce.com/) is similar. The server is +specified through a `P4PORT' parameter. Module and branch are +specified in a single depot path, and revisions are depot-wide. When +branches are used, the `p4base' and `defaultBranch' are concatenated +together to produce the depot path. + + Arch (http://wiki.gnuarch.org/) and Bazaar +(http://bazaar.canonical.com/) specify a repository by URL, as well +as a `version' which is kind of like a branch name. Arch uses the +word `archive' to represent the repository. Arch lets you push +changes from one archive to another, removing the strict +centralization required by CVS and SVN. It retains the distinction +between repository and working directory that most other VC systems +use. For complex multi-module directory structures, Arch has a +built-in `build config' layer with which the checkout process has two +steps. First, an initial bootstrap checkout is performed to retrieve +a set of build-config files. Second, one of these files is used to +figure out which archives/modules should be used to populate +subdirectories of the initial checkout. + + Builders which use Arch and Bazaar therefore have a static archive +`url', and a default "branch" (which is a string that specifies a +complete category-branch-version triple). Each build can have its own +branch (the category-branch-version string) to override the default, +as well as a revision number (which is turned into a -patch-NN suffix +when performing the checkout). + + Bzr (http://bazaar-vcs.org) (which is a descendant of Arch/Bazaar, +and is frequently referred to as "Bazaar") has the same sort of +repository-vs-workspace model as Arch, but the repository data can +either be stored inside the working directory or kept elsewhere +(either on the same machine or on an entirely different machine). For +the purposes of Buildbot (which never commits changes), the repository +is specified with a URL and a revision number. + + The most common way to obtain read-only access to a bzr tree is via +HTTP, simply by making the repository visible through a web server +like Apache. Bzr can also use FTP and SFTP servers, if the buildslave +process has sufficient privileges to access them. Higher performance +can be obtained by running a special Bazaar-specific server. None of +these matter to the buildbot: the repository URL just has to match the +kind of server being used. The `repoURL' argument provides the +location of the repository. + + Branches are expressed as subdirectories of the main central +repository, which means that if branches are being used, the BZR step +is given a `baseURL' and `defaultBranch' instead of getting the +`repoURL' argument. + + Darcs (http://darcs.net/) doesn't really have the notion of a +single master repository. Nor does it really have branches. In Darcs, +each working directory is also a repository, and there are operations +to push and pull patches from one of these `repositories' to another. +For the Buildbot's purposes, all you need to do is specify the URL of +a repository that you want to build from. The build slave will then +pull the latest patches from that repository and build them. Multiple +branches are implemented by using multiple repositories (possibly +living on the same server). + + Builders which use Darcs therefore have a static `repourl' which +specifies the location of the repository. If branches are being used, +the source Step is instead configured with a `baseURL' and a +`defaultBranch', and the two strings are simply concatenated together +to obtain the repository's URL. Each build then has a specific branch +which replaces `defaultBranch', or just uses the default one. Instead +of a revision number, each build can have a "context", which is a +string that records all the patches that are present in a given tree +(this is the output of `darcs changes --context', and is considerably +less concise than, e.g. Subversion's revision number, but the +patch-reordering flexibility of Darcs makes it impossible to provide +a shorter useful specification). + + Mercurial (http://selenic.com/mercurial) is like Darcs, in that +each branch is stored in a separate repository. The `repourl', +`baseURL', and `defaultBranch' arguments are all handled the same way +as with Darcs. The "revision", however, is the hash identifier +returned by `hg identify'. + + Git (http://git.or.cz/) also follows a decentralized model, and +each repository can have several branches and tags. The source Step is +configured with a static `repourl' which specifies the location of +the repository. In addition, an optional `branch' parameter can be +specified to check out code from a specific branch instead of the +default "master" branch. The "revision" is specified as a SHA1 hash +as returned by e.g. `git rev-parse'. No attempt is made to ensure +that the specified revision is actually a subset of the specified +branch. + + +File: buildbot.info, Node: Attributes of Changes, Prev: How Different VC Systems Specify Sources, Up: Version Control Systems + +3.1.4 Attributes of Changes +--------------------------- + +Who +=== + +Each Change has a `who' attribute, which specifies which developer is +responsible for the change. This is a string which comes from a +namespace controlled by the VC repository. Frequently this means it +is a username on the host which runs the repository, but not all VC +systems require this (Arch, for example, uses a fully-qualified `Arch +ID', which looks like an email address, as does Darcs). Each +StatusNotifier will map the `who' attribute into something +appropriate for their particular means of communication: an email +address, an IRC handle, etc. + +Files +===== + +It also has a list of `files', which are just the tree-relative +filenames of any files that were added, deleted, or modified for this +Change. These filenames are used by the `fileIsImportant' function +(in the Scheduler) to decide whether it is worth triggering a new +build or not, e.g. the function could use the following function to +only run a build if a C file were checked in: + + def has_C_files(change): + for name in change.files: + if name.endswith(".c"): + return True + return False + + Certain BuildSteps can also use the list of changed files to run a +more targeted series of tests, e.g. the `python_twisted.Trial' step +can run just the unit tests that provide coverage for the modified +.py files instead of running the full test suite. + +Comments +======== + +The Change also has a `comments' attribute, which is a string +containing any checkin comments. + +Revision +======== + +Each Change can have a `revision' attribute, which describes how to +get a tree with a specific state: a tree which includes this Change +(and all that came before it) but none that come after it. If this +information is unavailable, the `.revision' attribute will be `None'. +These revisions are provided by the ChangeSource, and consumed by the +`computeSourceRevision' method in the appropriate `step.Source' class. + +`CVS' + `revision' is an int, seconds since the epoch + +`SVN' + `revision' is an int, the changeset number (r%d) + +`Darcs' + `revision' is a large string, the output of `darcs changes + --context' + +`Mercurial' + `revision' is a short string (a hash ID), the output of `hg + identify' + +`Arch/Bazaar' + `revision' is the full revision ID (ending in -patch-%d) + +`P4' + `revision' is an int, the transaction number + +`Git' + `revision' is a short string (a SHA1 hash), the output of e.g. + `git rev-parse' + +Branches +======== + +The Change might also have a `branch' attribute. This indicates that +all of the Change's files are in the same named branch. The +Schedulers get to decide whether the branch should be built or not. + + For VC systems like CVS, Arch, Monotone, and Git, the `branch' +name is unrelated to the filename. (that is, the branch name and the +filename inhabit unrelated namespaces). For SVN, branches are +expressed as subdirectories of the repository, so the file's "svnurl" +is a combination of some base URL, the branch name, and the filename +within the branch. (In a sense, the branch name and the filename +inhabit the same namespace). Darcs branches are subdirectories of a +base URL just like SVN. Mercurial branches are the same as Darcs. + +`CVS' + branch='warner-newfeature', files=['src/foo.c'] + +`SVN' + branch='branches/warner-newfeature', files=['src/foo.c'] + +`Darcs' + branch='warner-newfeature', files=['src/foo.c'] + +`Mercurial' + branch='warner-newfeature', files=['src/foo.c'] + +`Arch/Bazaar' + branch='buildbot-usebranches-0', files=['buildbot/master.py'] + +`Git' + branch='warner-newfeature', files=['src/foo.c'] + +Links +===== + +Finally, the Change might have a `links' list, which is intended to +provide a list of URLs to a _viewcvs_-style web page that provides +more detail for this Change, perhaps including the full file diffs. + + +File: buildbot.info, Node: Schedulers, Next: BuildSet, Prev: Version Control Systems, Up: Concepts + +3.2 Schedulers +============== + +Each Buildmaster has a set of `Scheduler' objects, each of which gets +a copy of every incoming Change. The Schedulers are responsible for +deciding when Builds should be run. Some Buildbot installations might +have a single Scheduler, while others may have several, each for a +different purpose. + + For example, a "quick" scheduler might exist to give immediate +feedback to developers, hoping to catch obvious problems in the code +that can be detected quickly. These typically do not run the full test +suite, nor do they run on a wide variety of platforms. They also +usually do a VC update rather than performing a brand-new checkout +each time. You could have a "quick" scheduler which used a 30 second +timeout, and feeds a single "quick" Builder that uses a VC +`mode='update'' setting. + + A separate "full" scheduler would run more comprehensive tests a +little while later, to catch more subtle problems. This scheduler +would have a longer tree-stable-timer, maybe 30 minutes, and would +feed multiple Builders (with a `mode=' of `'copy'', `'clobber'', or +`'export''). + + The `tree-stable-timer' and `fileIsImportant' decisions are made +by the Scheduler. Dependencies are also implemented here. Periodic +builds (those which are run every N seconds rather than after new +Changes arrive) are triggered by a special `Periodic' Scheduler +subclass. The default Scheduler class can also be told to watch for +specific branches, ignoring Changes on other branches. This may be +useful if you have a trunk and a few release branches which should be +tracked, but when you don't want to have the Buildbot pay attention +to several dozen private user branches. + + When the setup has multiple sources of Changes the `category' can +be used for `Scheduler' objects to filter out a subset of the +Changes. Note that not all change sources can attach a category. + + Some Schedulers may trigger builds for other reasons, other than +recent Changes. For example, a Scheduler subclass could connect to a +remote buildmaster and watch for builds of a library to succeed before +triggering a local build that uses that library. + + Each Scheduler creates and submits `BuildSet' objects to the +`BuildMaster', which is then responsible for making sure the +individual `BuildRequests' are delivered to the target `Builders'. + + `Scheduler' instances are activated by placing them in the +`c['schedulers']' list in the buildmaster config file. Each Scheduler +has a unique name. + + +File: buildbot.info, Node: BuildSet, Next: BuildRequest, Prev: Schedulers, Up: Concepts + +3.3 BuildSet +============ + +A `BuildSet' is the name given to a set of Builds that all +compile/test the same version of the tree on multiple Builders. In +general, all these component Builds will perform the same sequence of +Steps, using the same source code, but on different platforms or +against a different set of libraries. + + The `BuildSet' is tracked as a single unit, which fails if any of +the component Builds have failed, and therefore can succeed only if +_all_ of the component Builds have succeeded. There are two kinds of +status notification messages that can be emitted for a BuildSet: the +`firstFailure' type (which fires as soon as we know the BuildSet will +fail), and the `Finished' type (which fires once the BuildSet has +completely finished, regardless of whether the overall set passed or +failed). + + A `BuildSet' is created with a _source stamp_ tuple of (branch, +revision, changes, patch), some of which may be None, and a list of +Builders on which it is to be run. They are then given to the +BuildMaster, which is responsible for creating a separate +`BuildRequest' for each Builder. + + There are a couple of different likely values for the +`SourceStamp': + +`(revision=None, changes=[CHANGES], patch=None)' + This is a `SourceStamp' used when a series of Changes have + triggered a build. The VC step will attempt to check out a tree + that contains CHANGES (and any changes that occurred before + CHANGES, but not any that occurred after them). + +`(revision=None, changes=None, patch=None)' + This builds the most recent code on the default branch. This is + the sort of `SourceStamp' that would be used on a Build that was + triggered by a user request, or a Periodic scheduler. It is also + possible to configure the VC Source Step to always check out the + latest sources rather than paying attention to the Changes in the + SourceStamp, which will result in same behavior as this. + +`(branch=BRANCH, revision=None, changes=None, patch=None)' + This builds the most recent code on the given BRANCH. Again, + this is generally triggered by a user request or Periodic build. + +`(revision=REV, changes=None, patch=(LEVEL, DIFF))' + This checks out the tree at the given revision REV, then applies + a patch (using `patch -pLEVEL <DIFF'). The *note try:: feature + uses this kind of `SourceStamp'. If `patch' is None, the patching + step is bypassed. + + + The buildmaster is responsible for turning the `BuildSet' into a +set of `BuildRequest' objects and queueing them on the appropriate +Builders. + + +File: buildbot.info, Node: BuildRequest, Next: Builder, Prev: BuildSet, Up: Concepts + +3.4 BuildRequest +================ + +A `BuildRequest' is a request to build a specific set of sources on a +single specific `Builder'. Each `Builder' runs the `BuildRequest' as +soon as it can (i.e. when an associated buildslave becomes free). +`BuildRequest's are prioritized from oldest to newest, so when a +buildslave becomes free, the `Builder' with the oldest `BuildRequest' +is run. + + The `BuildRequest' contains the `SourceStamp' specification. The +actual process of running the build (the series of Steps that will be +executed) is implemented by the `Build' object. In this future this +might be changed, to have the `Build' define _what_ gets built, and a +separate `BuildProcess' (provided by the Builder) to define _how_ it +gets built. + + `BuildRequest' is created with optional `Properties'. One of +these, `owner', is collected by the resultant `Build' and added to +the set of _interested users_ to which status notifications will be +sent, depending on the configuration for each status object. + + The `BuildRequest' may be mergeable with other compatible +`BuildRequest's. Builds that are triggered by incoming Changes will +generally be mergeable. Builds that are triggered by user requests +are generally not, unless they are multiple requests to build the +_latest sources_ of the same branch. + + +File: buildbot.info, Node: Builder, Next: Users, Prev: BuildRequest, Up: Concepts + +3.5 Builder +=========== + +The `Builder' is a long-lived object which controls all Builds of a +given type. Each one is created when the config file is first parsed, +and lives forever (or rather until it is removed from the config +file). It mediates the connections to the buildslaves that do all the +work, and is responsible for creating the `Build' objects that decide +_how_ a build is performed (i.e., which steps are executed in what +order). + + Each `Builder' gets a unique name, and the path name of a +directory where it gets to do all its work (there is a +buildmaster-side directory for keeping status information, as well as +a buildslave-side directory where the actual checkout/compile/test +commands are executed). It also gets a `BuildFactory', which is +responsible for creating new `Build' instances: because the `Build' +instance is what actually performs each build, choosing the +`BuildFactory' is the way to specify what happens each time a build +is done. + + Each `Builder' is associated with one of more `BuildSlaves'. A +`Builder' which is used to perform OS-X builds (as opposed to Linux +or Solaris builds) should naturally be associated with an OS-X-based +buildslave. + + A `Builder' may be given a set of environment variables to be used +in its *note ShellCommand::s. These variables will override anything +in the buildslave's environment. Variables passed directly to a +ShellCommand will override variables of the same name passed to the +Builder. + + For example, if you a pool of identical slaves it is often easier +to manage variables like PATH from Buildbot rather than manually +editing it inside of the slaves' environment. + + f = factory.BuildFactory + f.addStep(ShellCommand( + command=['bash', './configure'])) + f.addStep(Compile()) + + c['builders'] = [ + {'name': 'test', 'slavenames': ['slave1', 'slave2', 'slave3', 'slave4', + 'slave5', 'slave6'], + 'builddir': 'test', 'factory': f', + 'env': {'PATH': '/opt/local/bin:/opt/app/bin:/usr/local/bin:/usr/bin'}} + + +File: buildbot.info, Node: Users, Next: Build Properties, Prev: Builder, Up: Concepts + +3.6 Users +========= + +Buildbot has a somewhat limited awareness of _users_. It assumes the +world consists of a set of developers, each of whom can be described +by a couple of simple attributes. These developers make changes to +the source code, causing builds which may succeed or fail. + + Each developer is primarily known through the source control +system. Each Change object that arrives is tagged with a `who' field +that typically gives the account name (on the repository machine) of +the user responsible for that change. This string is the primary key +by which the User is known, and is displayed on the HTML status pages +and in each Build's "blamelist". + + To do more with the User than just refer to them, this username +needs to be mapped into an address of some sort. The responsibility +for this mapping is left up to the status module which needs the +address. The core code knows nothing about email addresses or IRC +nicknames, just user names. + +* Menu: + +* Doing Things With Users:: +* Email Addresses:: +* IRC Nicknames:: +* Live Status Clients:: + + +File: buildbot.info, Node: Doing Things With Users, Next: Email Addresses, Prev: Users, Up: Users + +3.6.1 Doing Things With Users +----------------------------- + +Each Change has a single User who is responsible for that Change. Most +Builds have a set of Changes: the Build represents the first time +these Changes have been built and tested by the Buildbot. The build +has a "blamelist" that consists of a simple union of the Users +responsible for all the Build's Changes. + + The Build provides (through the IBuildStatus interface) a list of +Users who are "involved" in the build. For now this is equal to the +blamelist, but in the future it will be expanded to include a "build +sheriff" (a person who is "on duty" at that time and responsible for +watching over all builds that occur during their shift), as well as +per-module owners who simply want to keep watch over their domain +(chosen by subdirectory or a regexp matched against the filenames +pulled out of the Changes). The Involved Users are those who probably +have an interest in the results of any given build. + + In the future, Buildbot will acquire the concept of "Problems", +which last longer than builds and have beginnings and ends. For +example, a test case which passed in one build and then failed in the +next is a Problem. The Problem lasts until the test case starts +passing again, at which point the Problem is said to be "resolved". + + If there appears to be a code change that went into the tree at the +same time as the test started failing, that Change is marked as being +resposible for the Problem, and the user who made the change is added +to the Problem's "Guilty" list. In addition to this user, there may +be others who share responsibility for the Problem (module owners, +sponsoring developers). In addition to the Responsible Users, there +may be a set of Interested Users, who take an interest in the fate of +the Problem. + + Problems therefore have sets of Users who may want to be kept +aware of the condition of the problem as it changes over time. If +configured, the Buildbot can pester everyone on the Responsible list +with increasing harshness until the problem is resolved, with the +most harshness reserved for the Guilty parties themselves. The +Interested Users may merely be told when the problem starts and +stops, as they are not actually responsible for fixing anything. + + +File: buildbot.info, Node: Email Addresses, Next: IRC Nicknames, Prev: Doing Things With Users, Up: Users + +3.6.2 Email Addresses +--------------------- + +The `buildbot.status.mail.MailNotifier' class (*note MailNotifier::) +provides a status target which can send email about the results of +each build. It accepts a static list of email addresses to which each +message should be delivered, but it can also be configured to send +mail to the Build's Interested Users. To do this, it needs a way to +convert User names into email addresses. + + For many VC systems, the User Name is actually an account name on +the system which hosts the repository. As such, turning the name into +an email address is a simple matter of appending +"@repositoryhost.com". Some projects use other kinds of mappings (for +example the preferred email address may be at "project.org" despite +the repository host being named "cvs.project.org"), and some VC +systems have full separation between the concept of a user and that +of an account on the repository host (like Perforce). Some systems +(like Arch) put a full contact email address in every change. + + To convert these names to addresses, the MailNotifier uses an +EmailLookup object. This provides a .getAddress method which accepts +a name and (eventually) returns an address. The default `MailNotifier' +module provides an EmailLookup which simply appends a static string, +configurable when the notifier is created. To create more complex +behaviors (perhaps using an LDAP lookup, or using "finger" on a +central host to determine a preferred address for the developer), +provide a different object as the `lookup' argument. + + In the future, when the Problem mechanism has been set up, the +Buildbot will need to send mail to arbitrary Users. It will do this +by locating a MailNotifier-like object among all the buildmaster's +status targets, and asking it to send messages to various Users. This +means the User-to-address mapping only has to be set up once, in your +MailNotifier, and every email message the buildbot emits will take +advantage of it. + + +File: buildbot.info, Node: IRC Nicknames, Next: Live Status Clients, Prev: Email Addresses, Up: Users + +3.6.3 IRC Nicknames +------------------- + +Like MailNotifier, the `buildbot.status.words.IRC' class provides a +status target which can announce the results of each build. It also +provides an interactive interface by responding to online queries +posted in the channel or sent as private messages. + + In the future, the buildbot can be configured map User names to IRC +nicknames, to watch for the recent presence of these nicknames, and to +deliver build status messages to the interested parties. Like +`MailNotifier' does for email addresses, the `IRC' object will have +an `IRCLookup' which is responsible for nicknames. The mapping can be +set up statically, or it can be updated by online users themselves +(by claiming a username with some kind of "buildbot: i am user +warner" commands). + + Once the mapping is established, the rest of the buildbot can ask +the `IRC' object to send messages to various users. It can report on +the likelihood that the user saw the given message (based upon how +long the user has been inactive on the channel), which might prompt +the Problem Hassler logic to send them an email message instead. + + +File: buildbot.info, Node: Live Status Clients, Prev: IRC Nicknames, Up: Users + +3.6.4 Live Status Clients +------------------------- + +The Buildbot also offers a PB-based status client interface which can +display real-time build status in a GUI panel on the developer's +desktop. This interface is normally anonymous, but it could be +configured to let the buildmaster know _which_ developer is using the +status client. The status client could then be used as a +message-delivery service, providing an alternative way to deliver +low-latency high-interruption messages to the developer (like "hey, +you broke the build"). + + +File: buildbot.info, Node: Build Properties, Prev: Users, Up: Concepts + +3.7 Build Properties +==================== + +Each build has a set of "Build Properties", which can be used by its +BuildStep to modify their actions. These properties, in the form of +key-value pairs, provide a general framework for dynamically altering +the behavior of a build based on its circumstances. + + Properties come from a number of places: + * global configuration - These properties apply to all builds. + + * schedulers - A scheduler can specify properties available to all + the builds it starts. + + * buildslaves - A buildslave can pass properties on to the builds + it performs. + + * builds - A build automatically sets a number of properties on + itself. + + * steps - Steps of a build can set properties that are available + to subsequent steps. In particular, source steps set a number + of properties. + + Properties are very flexible, and can be used to implement all +manner of functionality. Here are some examples: + + Most Source steps record the revision that they checked out in the +`got_revision' property. A later step could use this property to +specify the name of a fully-built tarball, dropped in an +easily-acessible directory for later testing. + + Some projects want to perform nightly builds as well as in response +to committed changes. Such a project would run two schedulers, both +pointing to the same set of builders, but could provide an +`is_nightly' property so that steps can distinguish the nightly +builds, perhaps to run more resource-intensive tests. + + Some projects have different build processes on different systems. +Rather than create a build factory for each slave, the steps can use +buildslave properties to identify the unique aspects of each slave +and adapt the build process dynamically. + + +File: buildbot.info, Node: Configuration, Next: Getting Source Code Changes, Prev: Concepts, Up: Top + +4 Configuration +*************** + +The buildbot's behavior is defined by the "config file", which +normally lives in the `master.cfg' file in the buildmaster's base +directory (but this can be changed with an option to the `buildbot +create-master' command). This file completely specifies which +Builders are to be run, which slaves they should use, how Changes +should be tracked, and where the status information is to be sent. +The buildmaster's `buildbot.tac' file names the base directory; +everything else comes from the config file. + + A sample config file was installed for you when you created the +buildmaster, but you will need to edit it before your buildbot will do +anything useful. + + This chapter gives an overview of the format of this file and the +various sections in it. You will need to read the later chapters to +understand how to fill in each section properly. + +* Menu: + +* Config File Format:: +* Loading the Config File:: +* Testing the Config File:: +* Defining the Project:: +* Change Sources and Schedulers:: +* Merging BuildRequests:: +* Setting the slaveport:: +* Buildslave Specifiers:: +* On-Demand ("Latent") Buildslaves:: +* Defining Global Properties:: +* Defining Builders:: +* Defining Status Targets:: +* Debug options:: + + +File: buildbot.info, Node: Config File Format, Next: Loading the Config File, Prev: Configuration, Up: Configuration + +4.1 Config File Format +====================== + +The config file is, fundamentally, just a piece of Python code which +defines a dictionary named `BuildmasterConfig', with a number of keys +that are treated specially. You don't need to know Python to do basic +configuration, though, you can just copy the syntax of the sample +file. If you _are_ comfortable writing Python code, however, you can +use all the power of a full programming language to achieve more +complicated configurations. + + The `BuildmasterConfig' name is the only one which matters: all +other names defined during the execution of the file are discarded. +When parsing the config file, the Buildmaster generally compares the +old configuration with the new one and performs the minimum set of +actions necessary to bring the buildbot up to date: Builders which are +not changed are left untouched, and Builders which are modified get to +keep their old event history. + + Basic Python syntax: comments start with a hash character ("#"), +tuples are defined with `(parenthesis, pairs)', arrays are defined +with `[square, brackets]', tuples and arrays are mostly +interchangeable. Dictionaries (data structures which map "keys" to +"values") are defined with curly braces: `{'key1': 'value1', 'key2': +'value2'} '. Function calls (and object instantiation) can use named +parameters, like `w = html.Waterfall(http_port=8010)'. + + The config file starts with a series of `import' statements, which +make various kinds of Steps and Status targets available for later +use. The main `BuildmasterConfig' dictionary is created, then it is +populated with a variety of keys. These keys are broken roughly into +the following sections, each of which is documented in the rest of +this chapter: + + * Project Definitions + + * Change Sources / Schedulers + + * Slaveport + + * Buildslave Configuration + + * Builders / Interlocks + + * Status Targets + + * Debug options + + The config file can use a few names which are placed into its +namespace: + +`basedir' + the base directory for the buildmaster. This string has not been + expanded, so it may start with a tilde. It needs to be expanded + before use. The config file is located in + `os.path.expanduser(os.path.join(basedir, 'master.cfg'))' + + + +File: buildbot.info, Node: Loading the Config File, Next: Testing the Config File, Prev: Config File Format, Up: Configuration + +4.2 Loading the Config File +=========================== + +The config file is only read at specific points in time. It is first +read when the buildmaster is launched. Once it is running, there are +various ways to ask it to reload the config file. If you are on the +system hosting the buildmaster, you can send a `SIGHUP' signal to it: +the `buildbot' tool has a shortcut for this: + + buildbot reconfig BASEDIR + + This command will show you all of the lines from `twistd.log' that +relate to the reconfiguration. If there are any problems during the +config-file reload, they will be displayed in these lines. + + The debug tool (`buildbot debugclient --master HOST:PORT') has a +"Reload .cfg" button which will also trigger a reload. In the future, +there will be other ways to accomplish this step (probably a +password-protected button on the web page, as well as a privileged IRC +command). + + When reloading the config file, the buildmaster will endeavor to +change as little as possible about the running system. For example, +although old status targets may be shut down and new ones started up, +any status targets that were not changed since the last time the +config file was read will be left running and untouched. Likewise any +Builders which have not been changed will be left running. If a +Builder is modified (say, the build process is changed) while a Build +is currently running, that Build will keep running with the old +process until it completes. Any previously queued Builds (or Builds +which get queued after the reconfig) will use the new process. + + +File: buildbot.info, Node: Testing the Config File, Next: Defining the Project, Prev: Loading the Config File, Up: Configuration + +4.3 Testing the Config File +=========================== + +To verify that the config file is well-formed and contains no +deprecated or invalid elements, use the "checkconfig" command: + + % buildbot checkconfig master.cfg + Config file is good! + + If the config file has deprecated features (perhaps because you've +upgraded the buildmaster and need to update the config file to match), +they will be announced by checkconfig. In this case, the config file +will work, but you should really remove the deprecated items and use +the recommended replacements instead: + + % buildbot checkconfig master.cfg + /usr/lib/python2.4/site-packages/buildbot/master.py:559: DeprecationWarning: c['sources'] is + deprecated as of 0.7.6 and will be removed by 0.8.0 . Please use c['change_source'] instead. + warnings.warn(m, DeprecationWarning) + Config file is good! + + If the config file is simply broken, that will be caught too: + + % buildbot checkconfig master.cfg + Traceback (most recent call last): + File "/usr/lib/python2.4/site-packages/buildbot/scripts/runner.py", line 834, in doCheckConfig + ConfigLoader(configFile) + File "/usr/lib/python2.4/site-packages/buildbot/scripts/checkconfig.py", line 31, in __init__ + self.loadConfig(configFile) + File "/usr/lib/python2.4/site-packages/buildbot/master.py", line 480, in loadConfig + exec f in localDict + File "/home/warner/BuildBot/master/foolscap/master.cfg", line 90, in ? + c[bogus] = "stuff" + NameError: name 'bogus' is not defined + + +File: buildbot.info, Node: Defining the Project, Next: Change Sources and Schedulers, Prev: Testing the Config File, Up: Configuration + +4.4 Defining the Project +======================== + +There are a couple of basic settings that you use to tell the buildbot +what project it is working on. This information is used by status +reporters to let users find out more about the codebase being +exercised by this particular Buildbot installation. + + c['projectName'] = "Buildbot" + c['projectURL'] = "http://buildbot.sourceforge.net/" + c['buildbotURL'] = "http://localhost:8010/" + + `projectName' is a short string will be used to describe the +project that this buildbot is working on. For example, it is used as +the title of the waterfall HTML page. + + `projectURL' is a string that gives a URL for the project as a +whole. HTML status displays will show `projectName' as a link to +`projectURL', to provide a link from buildbot HTML pages to your +project's home page. + + The `buildbotURL' string should point to the location where the +buildbot's internal web server (usually the `html.Waterfall' page) is +visible. This typically uses the port number set when you create the +`Waterfall' object: the buildbot needs your help to figure out a +suitable externally-visible host name. + + When status notices are sent to users (either by email or over +IRC), `buildbotURL' will be used to create a URL to the specific build +or problem that they are being notified about. It will also be made +available to queriers (over IRC) who want to find out where to get +more information about this buildbot. + + The `logCompressionLimit' enables bz2-compression of build logs on +disk for logs that are bigger than the given size, or disables that +completely if given `False'. The default value is 4k, which should be +a reasonable default on most file systems. This setting has no impact +on status plugins, and merely affects the required disk space on the +master for build logs. + + +File: buildbot.info, Node: Change Sources and Schedulers, Next: Merging BuildRequests, Prev: Defining the Project, Up: Configuration + +4.5 Change Sources and Schedulers +================================= + +The `c['change_source']' key is the ChangeSource instance(1) that +defines how the buildmaster learns about source code changes. More +information about what goes here is available in *Note Getting Source +Code Changes::. + + from buildbot.changes.pb import PBChangeSource + c['change_source'] = PBChangeSource() + + (note: in buildbot-0.7.5 and earlier, this key was named +`c['sources']', and required a list. `c['sources']' is deprecated as +of buildbot-0.7.6 and is scheduled to be removed in a future release). + + `c['schedulers']' is a list of Scheduler instances, each of which +causes builds to be started on a particular set of Builders. The two +basic Scheduler classes you are likely to start with are `Scheduler' +and `Periodic', but you can write a customized subclass to implement +more complicated build scheduling. + + Scheduler arguments should always be specified by name (as keyword +arguments), to allow for future expansion: + + sched = Scheduler(name="quick", builderNames=['lin', 'win']) + + All schedulers have several arguments in common: + +`name' + Each Scheduler must have a unique name. This is used in status + displays, and is also available in the build property + `scheduler'. + +`builderNames' + This is the set of builders which this scheduler should trigger, + specified as a list of names (strings). + +`properties' + This is a dictionary specifying properties that will be + transmitted to all builds started by this scheduler. + + + Here is a brief catalog of the available Scheduler types. All these +Schedulers are classes in `buildbot.scheduler', and the docstrings +there are the best source of documentation on the arguments taken by +each one. + +* Menu: + +* Scheduler Scheduler:: +* AnyBranchScheduler:: +* Dependent Scheduler:: +* Periodic Scheduler:: +* Nightly Scheduler:: +* Try Schedulers:: +* Triggerable Scheduler:: + + ---------- Footnotes ---------- + + (1) To be precise, it is an object or a list of objects which all +implement the `buildbot.interfaces.IChangeSource' Interface. It is +unusual to have multiple ChangeSources, so this key accepts either a +single ChangeSource or a sequence of them. + + +File: buildbot.info, Node: Scheduler Scheduler, Next: AnyBranchScheduler, Prev: Change Sources and Schedulers, Up: Change Sources and Schedulers + +4.5.1 Scheduler Scheduler +------------------------- + +This is the original and still most popular Scheduler class. It +follows exactly one branch, and starts a configurable +tree-stable-timer after each change on that branch. When the timer +expires, it starts a build on some set of Builders. The Scheduler +accepts a `fileIsImportant' function which can be used to ignore some +Changes if they do not affect any "important" files. + + The arguments to this scheduler are: + +`name' + +`builderNames' + +`properties' + +`branch' + This Scheduler will pay attention to a single branch, ignoring + Changes that occur on other branches. Setting `branch' equal to + the special value of `None' means it should only pay attention to + the default branch. Note that `None' is a keyword, not a string, + so you want to use `None' and not `"None"'. + +`treeStableTimer' + The Scheduler will wait for this many seconds before starting the + build. If new changes are made during this interval, the timer + will be restarted, so really the build will be started after a + change and then after this many seconds of inactivity. + +`fileIsImportant' + A callable which takes one argument, a Change instance, and + returns `True' if the change is worth building, and `False' if + it is not. Unimportant Changes are accumulated until the build + is triggered by an important change. The default value of None + means that all Changes are important. + +`categories' + A list of categories of changes that this scheduler will respond + to. If this is specified, then any non-matching changes are + ignored. + + + Example: + + from buildbot import scheduler + quick = scheduler.Scheduler(name="quick", + branch=None, + treeStableTimer=60, + builderNames=["quick-linux", "quick-netbsd"]) + full = scheduler.Scheduler(name="full", + branch=None, + treeStableTimer=5*60, + builderNames=["full-linux", "full-netbsd", "full-OSX"]) + c['schedulers'] = [quick, full] + + In this example, the two "quick" builders are triggered 60 seconds +after the tree has been changed. The "full" builds do not run quite +so quickly (they wait 5 minutes), so hopefully if the quick builds +fail due to a missing file or really simple typo, the developer can +discover and fix the problem before the full builds are started. Both +Schedulers only pay attention to the default branch: any changes on +other branches are ignored by these Schedulers. Each Scheduler +triggers a different set of Builders, referenced by name. + + +File: buildbot.info, Node: AnyBranchScheduler, Next: Dependent Scheduler, Prev: Scheduler Scheduler, Up: Change Sources and Schedulers + +4.5.2 AnyBranchScheduler +------------------------ + +This scheduler uses a tree-stable-timer like the default one, but +follows multiple branches at once. Each branch gets a separate timer. + + The arguments to this scheduler are: + +`name' + +`builderNames' + +`properties' + +`branches' + This Scheduler will pay attention to any number of branches, + ignoring Changes that occur on other branches. Branches are + specified just as for the `Scheduler' class. + +`treeStableTimer' + The Scheduler will wait for this many seconds before starting the + build. If new changes are made during this interval, the timer + will be restarted, so really the build will be started after a + change and then after this many seconds of inactivity. + +`fileIsImportant' + A callable which takes one argument, a Change instance, and + returns `True' if the change is worth building, and `False' if + it is not. Unimportant Changes are accumulated until the build + is triggered by an important change. The default value of None + means that all Changes are important. + + +File: buildbot.info, Node: Dependent Scheduler, Next: Periodic Scheduler, Prev: AnyBranchScheduler, Up: Change Sources and Schedulers + +4.5.3 Dependent Scheduler +------------------------- + +It is common to wind up with one kind of build which should only be +performed if the same source code was successfully handled by some +other kind of build first. An example might be a packaging step: you +might only want to produce .deb or RPM packages from a tree that was +known to compile successfully and pass all unit tests. You could put +the packaging step in the same Build as the compile and testing steps, +but there might be other reasons to not do this (in particular you +might have several Builders worth of compiles/tests, but only wish to +do the packaging once). Another example is if you want to skip the +"full" builds after a failing "quick" build of the same source code. +Or, if one Build creates a product (like a compiled library) that is +used by some other Builder, you'd want to make sure the consuming +Build is run _after_ the producing one. + + You can use "Dependencies" to express this relationship to the +Buildbot. There is a special kind of Scheduler named +`scheduler.Dependent' that will watch an "upstream" Scheduler for +builds to complete successfully (on all of its Builders). Each time +that happens, the same source code (i.e. the same `SourceStamp') will +be used to start a new set of builds, on a different set of Builders. +This "downstream" scheduler doesn't pay attention to Changes at all. +It only pays attention to the upstream scheduler. + + If the build fails on any of the Builders in the upstream set, the +downstream builds will not fire. Note that, for SourceStamps +generated by a ChangeSource, the `revision' is None, meaning HEAD. +If any changes are committed between the time the upstream scheduler +begins its build and the time the dependent scheduler begins its +build, then those changes will be included in the downstream build. +See the *note Triggerable Scheduler:: for a more flexible dependency +mechanism that can avoid this problem. + + The arguments to this scheduler are: + +`name' + +`builderNames' + +`properties' + +`upstream' + The upstream scheduler to watch. Note that this is an + "instance", not the name of the scheduler. + + Example: + + from buildbot import scheduler + tests = scheduler.Scheduler("just-tests", None, 5*60, + ["full-linux", "full-netbsd", "full-OSX"]) + package = scheduler.Dependent("build-package", + tests, # upstream scheduler -- no quotes! + ["make-tarball", "make-deb", "make-rpm"]) + c['schedulers'] = [tests, package] + + +File: buildbot.info, Node: Periodic Scheduler, Next: Nightly Scheduler, Prev: Dependent Scheduler, Up: Change Sources and Schedulers + +4.5.4 Periodic Scheduler +------------------------ + +This simple scheduler just triggers a build every N seconds. + + The arguments to this scheduler are: + +`name' + +`builderNames' + +`properties' + +`periodicBuildTimer' + The time, in seconds, after which to start a build. + + Example: + + from buildbot import scheduler + nightly = scheduler.Periodic(name="nightly", + builderNames=["full-solaris"], + periodicBuildTimer=24*60*60) + c['schedulers'] = [nightly] + + The Scheduler in this example just runs the full solaris build once +per day. Note that this Scheduler only lets you control the time +between builds, not the absolute time-of-day of each Build, so this +could easily wind up a "daily" or "every afternoon" scheduler +depending upon when it was first activated. + + +File: buildbot.info, Node: Nightly Scheduler, Next: Try Schedulers, Prev: Periodic Scheduler, Up: Change Sources and Schedulers + +4.5.5 Nightly Scheduler +----------------------- + +This is highly configurable periodic build scheduler, which triggers +a build at particular times of day, week, month, or year. The +configuration syntax is very similar to the well-known `crontab' +format, in which you provide values for minute, hour, day, and month +(some of which can be wildcards), and a build is triggered whenever +the current time matches the given constraints. This can run a build +every night, every morning, every weekend, alternate Thursdays, on +your boss's birthday, etc. + + Pass some subset of `minute', `hour', `dayOfMonth', `month', and +`dayOfWeek'; each may be a single number or a list of valid values. +The builds will be triggered whenever the current time matches these +values. Wildcards are represented by a '*' string. All fields default +to a wildcard except 'minute', so with no fields this defaults to a +build every hour, on the hour. The full list of parameters is: + +`name' + +`builderNames' + +`properties' + +`branch' + The branch to build, just as for `Scheduler'. + +`minute' + The minute of the hour on which to start the build. This + defaults to 0, meaning an hourly build. + +`hour' + The hour of the day on which to start the build, in 24-hour + notation. This defaults to *, meaning every hour. + +`month' + The month in which to start the build, with January = 1. This + defaults to *, meaning every month. + +`dayOfWeek' + The day of the week to start a build, with Monday = 0. This + defauls to *, meaning every day of the week. + +`onlyIfChanged' + If this is true, then builds will not be scheduled at the + designated time unless the source has changed since the previous + build. + + For example, the following master.cfg clause will cause a build to +be started every night at 3:00am: + + s = scheduler.Nightly(name='nightly', + builderNames=['builder1', 'builder2'], + hour=3, + minute=0) + + This scheduler will perform a build each monday morning at 6:23am +and again at 8:23am, but only if someone has committed code in the +interim: + + s = scheduler.Nightly(name='BeforeWork', + builderNames=['builder1'], + dayOfWeek=0, + hour=[6,8], + minute=23, + onlyIfChanged=True) + + The following runs a build every two hours, using Python's `range' +function: + + s = Nightly(name='every2hours', + builderNames=['builder1'], + hour=range(0, 24, 2)) + + Finally, this example will run only on December 24th: + + s = Nightly(name='SleighPreflightCheck', + builderNames=['flying_circuits', 'radar'], + month=12, + dayOfMonth=24, + hour=12, + minute=0) + + +File: buildbot.info, Node: Try Schedulers, Next: Triggerable Scheduler, Prev: Nightly Scheduler, Up: Change Sources and Schedulers + +4.5.6 Try Schedulers +-------------------- + +This scheduler allows developers to use the `buildbot try' command to +trigger builds of code they have not yet committed. See *note try:: +for complete details. + + Two implementations are available: `Try_Jobdir' and +`Try_Userpass'. The former monitors a job directory, specified by +the `jobdir' parameter, while the latter listens for PB connections +on a specific `port', and authenticates against `userport'. + + +File: buildbot.info, Node: Triggerable Scheduler, Prev: Try Schedulers, Up: Change Sources and Schedulers + +4.5.7 Triggerable Scheduler +--------------------------- + +The `Triggerable' scheduler waits to be triggered by a Trigger step +(see *note Triggering Schedulers::) in another build. That step can +optionally wait for the scheduler's builds to complete. This provides +two advantages over Dependent schedulers. First, the same scheduler +can be triggered from multiple builds. Second, the ability to wait +for a Triggerable's builds to complete provides a form of "subroutine +call", where one or more builds can "call" a scheduler to perform +some work for them, perhaps on other buildslaves. + + The parameters are just the basics: + +`name' + +`builderNames' + +`properties' + + This class is only useful in conjunction with the `Trigger' step. +Here is a fully-worked example: + + from buildbot import scheduler + from buildbot.process import factory + from buildbot.steps import trigger + + checkin = scheduler.Scheduler(name="checkin", + branch=None, + treeStableTimer=5*60, + builderNames=["checkin"]) + nightly = scheduler.Nightly(name='nightly', + builderNames=['nightly'], + hour=3, + minute=0) + + mktarball = scheduler.Triggerable(name="mktarball", + builderNames=["mktarball"]) + build = scheduler.Triggerable(name="build-all-platforms", + builderNames=["build-all-platforms"]) + test = scheduler.Triggerable(name="distributed-test", + builderNames=["distributed-test"]) + package = scheduler.Triggerable(name="package-all-platforms", + builderNames=["package-all-platforms"]) + + c['schedulers'] = [checkin, nightly, build, test, package] + + # on checkin, make a tarball, build it, and test it + checkin_factory = factory.BuildFactory() + checkin_factory.addStep(trigger.Trigger(schedulerNames=['mktarball'], + waitForFinish=True)) + checkin_factory.addStep(trigger.Trigger(schedulerNames=['build-all-platforms'], + waitForFinish=True)) + checkin_factory.addStep(trigger.Trigger(schedulerNames=['distributed-test'], + waitForFinish=True)) + + # and every night, make a tarball, build it, and package it + nightly_factory = factory.BuildFactory() + nightly_factory.addStep(trigger.Trigger(schedulerNames=['mktarball'], + waitForFinish=True)) + nightly_factory.addStep(trigger.Trigger(schedulerNames=['build-all-platforms'], + waitForFinish=True)) + nightly_factory.addStep(trigger.Trigger(schedulerNames=['package-all-platforms'], + waitForFinish=True)) + + +File: buildbot.info, Node: Merging BuildRequests, Next: Setting the slaveport, Prev: Change Sources and Schedulers, Up: Configuration + +4.6 Merging BuildRequests +========================= + +By default, buildbot merges BuildRequests that have the compatible +SourceStamps. This behaviour can be customized with the +`c['mergeRequests']' configuration key. This key specifies a function +which is caleld with three arguments: a `Builder' and two +`BuildRequest' objects. It should return true if the requests can be +merged. For example: + + def mergeRequests(builder, req1, req2): + """Don't merge buildrequest at all""" + return False + c['mergeRequests'] = mergeRequests + + In many cases, the details of the SourceStamps and BuildRequests +are important. In this example, only BuildRequests with the same +"reason" are merged; thus developers forcing builds for different +reasons will see distinct builds. + + def mergeRequests(builder, req1, req2): + if req1.source.canBeMergedWith(req2.source) and req1.reason == req2.reason: + return True + return False + c['mergeRequests'] = mergeRequests + + +File: buildbot.info, Node: Setting the slaveport, Next: Buildslave Specifiers, Prev: Merging BuildRequests, Up: Configuration + +4.7 Setting the slaveport +========================= + +The buildmaster will listen on a TCP port of your choosing for +connections from buildslaves. It can also use this port for +connections from remote Change Sources, status clients, and debug +tools. This port should be visible to the outside world, and you'll +need to tell your buildslave admins about your choice. + + It does not matter which port you pick, as long it is externally +visible, however you should probably use something larger than 1024, +since most operating systems don't allow non-root processes to bind to +low-numbered ports. If your buildmaster is behind a firewall or a NAT +box of some sort, you may have to configure your firewall to permit +inbound connections to this port. + + c['slavePortnum'] = 10000 + + `c['slavePortnum']' is a _strports_ specification string, defined +in the `twisted.application.strports' module (try `pydoc +twisted.application.strports' to get documentation on the format). +This means that you can have the buildmaster listen on a +localhost-only port by doing: + + c['slavePortnum'] = "tcp:10000:interface=127.0.0.1" + + This might be useful if you only run buildslaves on the same +machine, and they are all configured to contact the buildmaster at +`localhost:10000'. + + +File: buildbot.info, Node: Buildslave Specifiers, Next: On-Demand ("Latent") Buildslaves, Prev: Setting the slaveport, Up: Configuration + +4.8 Buildslave Specifiers +========================= + +The `c['slaves']' key is a list of known buildslaves. In the common +case, each buildslave is defined by an instance of the BuildSlave +class. It represents a standard, manually started machine that will +try to connect to the buildbot master as a slave. Contrast these +with the "on-demand" latent buildslaves, such as the Amazon Web +Service Elastic Compute Cloud latent buildslave discussed below. + + The BuildSlave class is instantiated with two values: (slavename, +slavepassword). These are the same two values that need to be +provided to the buildslave administrator when they create the +buildslave. + + The slavenames must be unique, of course. The password exists to +prevent evildoers from interfering with the buildbot by inserting +their own (broken) buildslaves into the system and thus displacing the +real ones. + + Buildslaves with an unrecognized slavename or a non-matching +password will be rejected when they attempt to connect, and a message +describing the problem will be put in the log file (see *note +Logfiles::). + + from buildbot.buildslave import BuildSlave + c['slaves'] = [BuildSlave('bot-solaris', 'solarispasswd') + BuildSlave('bot-bsd', 'bsdpasswd') + ] + + `BuildSlave' objects can also be created with an optional +`properties' argument, a dictionary specifying properties that will +be available to any builds performed on this slave. For example: + + from buildbot.buildslave import BuildSlave + c['slaves'] = [BuildSlave('bot-solaris', 'solarispasswd', + properties={'os':'solaris'}), + ] + + The `BuildSlave' constructor can also take an optional +`max_builds' parameter to limit the number of builds that it will +execute simultaneously: + + from buildbot.buildslave import BuildSlave + c['slaves'] = [BuildSlave("bot-linux", "linuxpassword", max_builds=2)] + + Historical note: in buildbot-0.7.5 and earlier, the `c['bots']' +key was used instead, and it took a list of (name, password) tuples. +This key is accepted for backwards compatibility, but is deprecated as +of 0.7.6 and will go away in some future release. + +* Menu: + +* When Buildslaves Go Missing:: + + +File: buildbot.info, Node: When Buildslaves Go Missing, Up: Buildslave Specifiers + +4.8.1 When Buildslaves Go Missing +--------------------------------- + +Sometimes, the buildslaves go away. One very common reason for this is +when the buildslave process is started once (manually) and left +running, but then later the machine reboots and the process is not +automatically restarted. + + If you'd like to have the administrator of the buildslave (or other +people) be notified by email when the buildslave has been missing for +too long, just add the `notify_on_missing=' argument to the +`BuildSlave' definition: + + c['slaves'] = [BuildSlave('bot-solaris', 'solarispasswd', + notify_on_missing="bob@example.com"), + ] + + By default, this will send email when the buildslave has been +disconnected for more than one hour. Only one email per +connection-loss event will be sent. To change the timeout, use +`missing_timeout=' and give it a number of seconds (the default is +3600). + + You can have the buildmaster send email to multiple recipients: +just provide a list of addresses instead of a single one: + + c['slaves'] = [BuildSlave('bot-solaris', 'solarispasswd', + notify_on_missing=["bob@example.com", + "alice@example.org"], + missing_timeout=300, # notify after 5 minutes + ), + ] + + The email sent this way will use a MailNotifier (*note +MailNotifier::) status target, if one is configured. This provides a +way for you to control the "from" address of the email, as well as +the relayhost (aka "smarthost") to use as an SMTP server. If no +MailNotifier is configured on this buildmaster, the +buildslave-missing emails will be sent using a default configuration. + + Note that if you want to have a MailNotifier for buildslave-missing +emails but not for regular build emails, just create one with +builders=[], as follows: + + from buildbot.status import mail + m = mail.MailNotifier(fromaddr="buildbot@localhost", builders=[], + relayhost="smtp.example.org") + c['status'].append(m) + c['slaves'] = [BuildSlave('bot-solaris', 'solarispasswd', + notify_on_missing="bob@example.com"), + ] + + +File: buildbot.info, Node: On-Demand ("Latent") Buildslaves, Next: Defining Global Properties, Prev: Buildslave Specifiers, Up: Configuration + +4.9 On-Demand ("Latent") Buildslaves +==================================== + +The standard buildbot model has slaves started manually. The +previous section described how to configure the master for this +approach. + + Another approach is to let the buildbot master start slaves when +builds are ready, on-demand. Thanks to services such as Amazon Web +Services' Elastic Compute Cloud ("AWS EC2"), this is relatively easy +to set up, and can be very useful for some situations. + + The buildslaves that are started on-demand are called "latent" +buildslaves. As of this writing, buildbot ships with an abstract +base class for building latent buildslaves, and a concrete +implementation for AWS EC2. + +* Menu: + +* Amazon Web Services Elastic Compute Cloud ("AWS EC2"):: +* Dangers with Latent Buildslaves:: +* Writing New Latent Buildslaves:: + + +File: buildbot.info, Node: Amazon Web Services Elastic Compute Cloud ("AWS EC2"), Next: Dangers with Latent Buildslaves, Up: On-Demand ("Latent") Buildslaves + +4.9.1 Amazon Web Services Elastic Compute Cloud ("AWS EC2") +----------------------------------------------------------- + +AWS EC2 is a web service that allows you to start virtual machines in +an Amazon data center. Please see their website for details, incuding +costs. Using the AWS EC2 latent buildslaves involves getting an EC2 +account with AWS and setting up payment; customizing one or more EC2 +machine images ("AMIs") on your desired operating system(s) and +publishing them (privately if needed); and configuring the buildbot +master to know how to start your customized images for +"substantiating" your latent slaves. + +* Menu: + +* Get an AWS EC2 Account:: +* Create an AMI:: +* Configure the Master with an EC2LatentBuildSlave:: + + +File: buildbot.info, Node: Get an AWS EC2 Account, Next: Create an AMI, Up: Amazon Web Services Elastic Compute Cloud ("AWS EC2") + +4.9.1.1 Get an AWS EC2 Account +.............................. + +To start off, to use the AWS EC2 latent buildslave, you need to get +an AWS developer account and sign up for EC2. These instructions may +help you get started: + + * Go to http://aws.amazon.com/ and click to "Sign Up Now" for an + AWS account. + + * Once you are logged into your account, you need to sign up for + EC2. Instructions for how to do this have changed over time + because Amazon changes their website, so the best advice is to + hunt for it. After signing up for EC2, it may say it wants you + to upload an x.509 cert. You will need this to create images + (see below) but it is not technically necessary for the buildbot + master configuration. + + * You must enter a valid credit card before you will be able to + use EC2. Do that under 'Payment Method'. + + * Make sure you're signed up for EC2 by going to 'Your + Account'->'Account Activity' and verifying EC2 is listed. + + +File: buildbot.info, Node: Create an AMI, Next: Configure the Master with an EC2LatentBuildSlave, Prev: Get an AWS EC2 Account, Up: Amazon Web Services Elastic Compute Cloud ("AWS EC2") + +4.9.1.2 Create an AMI +..................... + +Now you need to create an AMI and configure the master. You may need +to run through this cycle a few times to get it working, but these +instructions should get you started. + + Creating an AMI is out of the scope of this document. The EC2 +Getting Started Guide is a good resource for this task. Here are a +few additional hints. + + * When an instance of the image starts, it needs to automatically + start a buildbot slave that connects to your master (to create a + buildbot slave, *note Creating a buildslave::; to make a daemon, + *note Launching the daemons::). + + * You may want to make an instance of the buildbot slave, + configure it as a standard buildslave in the master (i.e., not + as a latent slave), and test and debug it that way before you + turn it into an AMI and convert to a latent slave in the master. + + +File: buildbot.info, Node: Configure the Master with an EC2LatentBuildSlave, Prev: Create an AMI, Up: Amazon Web Services Elastic Compute Cloud ("AWS EC2") + +4.9.1.3 Configure the Master with an EC2LatentBuildSlave +........................................................ + +Now let's assume you have an AMI that should work with the +EC2LatentBuildSlave. It's now time to set up your buildbot master +configuration. + + You will need some information from your AWS account: the "Access +Key Id" and the "Secret Access Key". If you've built the AMI +yourself, you probably already are familiar with these values. If +you have not, and someone has given you access to an AMI, these hints +may help you find the necessary values: + + * While logged into your AWS account, find the "Access + Identifiers" link (either on the left, or via "Your Account" -> + "Access Identifiers". + + * On the page, you'll see alphanumeric values for "Your Access Key + Id:" and "Your Secret Access Key:". Make a note of these. Later + on, we'll call the first one your "identifier" and the second + one your "secret_identifier." + + When creating an EC2LatentBuildSlave in the buildbot master +configuration, the first three arguments are required. The name and +password are the first two arguments, and work the same as with +normal buildslaves. The next argument specifies the type of the EC2 +virtual machine (available options as of this writing include +"m1.small", "m1.large", 'm1.xlarge", "c1.medium", and "c1.xlarge"; +see the EC2 documentation for descriptions of these machines). + + Here is the simplest example of configuring an EC2 latent +buildslave. It specifies all necessary remaining values explicitly in +the instantiation. + + from buildbot.ec2buildslave import EC2LatentBuildSlave + c['slaves'] = [EC2LatentBuildSlave('bot1', 'sekrit', 'm1.large', + ami='ami-12345', + identifier='publickey', + secret_identifier='privatekey' + )] + + The "ami" argument specifies the AMI that the master should start. +The "identifier" argument specifies the AWS "Access Key Id," and the +"secret_identifier" specifies the AWS "Secret Access Key." Both the +AMI and the account information can be specified in alternate ways. + + Note that whoever has your identifier and secret_identifier values +can request AWS work charged to your account, so these values need to +be carefully protected. Another way to specify these access keys is +to put them in a separate file. You can then make the access +privileges stricter for this separate file, and potentially let more +people read your main configuration file. + + By default, you can make an .ec2 directory in the home folder of +the user running the buildbot master. In that directory, create a +file called aws_id. The first line of that file should be your +access key id; the second line should be your secret access key id. +Then you can instantiate the build slave as follows. + + from buildbot.ec2buildslave import EC2LatentBuildSlave + c['slaves'] = [EC2LatentBuildSlave('bot1', 'sekrit', 'm1.large', + ami='ami-12345')] + + If you want to put the key information in another file, use the +"aws_id_file_path" initialization argument. + + Previous examples used a particular AMI. If the Buildbot master +will be deployed in a process-controlled environment, it may be +convenient to specify the AMI more flexibly. Rather than specifying +an individual AMI, specify one or two AMI filters. + + In all cases, the AMI that sorts last by its location (the S3 +bucket and manifest name) will be preferred. + + One available filter is to specify the acceptable AMI owners, by +AWS account number (the 12 digit number, usually rendered in AWS with +hyphens like "1234-5678-9012", should be entered as in integer). + + from buildbot.ec2buildslave import EC2LatentBuildSlave + bot1 = EC2LatentBuildSlave('bot1', 'sekrit', 'm1.large', + valid_ami_owners=[11111111111, + 22222222222], + identifier='publickey', + secret_identifier='privatekey' + ) + + The other available filter is to provide a regular expression +string that will be matched against each AMI's location (the S3 +bucket and manifest name). + + from buildbot.ec2buildslave import EC2LatentBuildSlave + bot1 = EC2LatentBuildSlave( + 'bot1', 'sekrit', 'm1.large', + valid_ami_location_regex=r'buildbot\-.*/image.manifest.xml', + identifier='publickey', secret_identifier='privatekey') + + The regular expression can specify a group, which will be +preferred for the sorting. Only the first group is used; subsequent +groups are ignored. + + from buildbot.ec2buildslave import EC2LatentBuildSlave + bot1 = EC2LatentBuildSlave( + 'bot1', 'sekrit', 'm1.large', + valid_ami_location_regex=r'buildbot\-.*\-(.*)/image.manifest.xml', + identifier='publickey', secret_identifier='privatekey') + + If the group can be cast to an integer, it will be. This allows +10 to sort after 1, for instance. + + from buildbot.ec2buildslave import EC2LatentBuildSlave + bot1 = EC2LatentBuildSlave( + 'bot1', 'sekrit', 'm1.large', + valid_ami_location_regex=r'buildbot\-.*\-(\d+)/image.manifest.xml', + identifier='publickey', secret_identifier='privatekey') + + In addition to using the password as a handshake between the +master and the slave, you may want to use a firewall to assert that +only machines from a specific IP can connect as slaves. This is +possible with AWS EC2 by using the Elastic IP feature. To configure, +generate a Elastic IP in AWS, and then specify it in your +configuration using the "elastic_ip" argument. + + from buildbot.ec2buildslave import EC2LatentBuildSlave + c['slaves'] = [EC2LatentBuildSlave('bot1', 'sekrit', 'm1.large', + 'ami-12345', + identifier='publickey', + secret_identifier='privatekey', + elastic_ip='208.77.188.166' + )] + + The EC2LatentBuildSlave supports all other configuration from the +standard BuildSlave. The "missing_timeout" and "notify_on_missing" +specify how long to wait for an EC2 instance to attach before +considering the attempt to have failed, and email addresses to alert, +respectively. "missing_timeout" defaults to 20 minutes. + + The "build_wait_timeout" allows you to specify how long an +EC2LatentBuildSlave should wait after a build for another build +before it shuts down the EC2 instance. It defaults to 10 minutes. + + "keypair_name" and "security_name" allow you to specify different +names for these AWS EC2 values. They both default to +"latent_buildbot_slave". + + +File: buildbot.info, Node: Dangers with Latent Buildslaves, Next: Writing New Latent Buildslaves, Prev: Amazon Web Services Elastic Compute Cloud ("AWS EC2"), Up: On-Demand ("Latent") Buildslaves + +4.9.2 Dangers with Latent Buildslaves +------------------------------------- + +Any latent build slave that interacts with a for-fee service, such as +the EC2LatentBuildSlave, brings significant risks. As already +identified, the configuraton will need access to account information +that, if obtained by a criminal, can be used to charge services to +your account. Also, bugs in the buildbot software may lead to +unnecessary charges. In particular, if the master neglects to shut +down an instance for some reason, a virtual machine may be running +unnecessarily, charging against your account. Manual and/or automatic +(e.g. nagios with a plugin using a library like boto) double-checking +may be appropriate. + + A comparitively trivial note is that currently if two instances +try to attach to the same latent buildslave, it is likely that the +system will become confused. This should not occur, unless, for +instance, you configure a normal build slave to connect with the +authentication of a latent buildbot. If the situation occurs, stop +all attached instances and restart the master. + + +File: buildbot.info, Node: Writing New Latent Buildslaves, Prev: Dangers with Latent Buildslaves, Up: On-Demand ("Latent") Buildslaves + +4.9.3 Writing New Latent Buildslaves +------------------------------------ + +Writing a new latent buildslave should only require subclassing +`buildbot.buildslave.AbstractLatentBuildSlave' and implementing +start_instance and stop_instance. + + def start_instance(self): + # responsible for starting instance that will try to connect with this + # master. Should return deferred. Problems should use an errback. The + # callback value can be None, or can be an iterable of short strings to + # include in the "substantiate success" status message, such as + # identifying the instance that started. + raise NotImplementedError + + def stop_instance(self, fast=False): + # responsible for shutting down instance. Return a deferred. If `fast`, + # we're trying to shut the master down, so callback as soon as is safe. + # Callback value is ignored. + raise NotImplementedError + + See `buildbot.ec2buildslave.EC2LatentBuildSlave' for an example, +or see the test example `buildbot.test_slaves.FakeLatentBuildSlave'. + + +File: buildbot.info, Node: Defining Global Properties, Next: Defining Builders, Prev: On-Demand ("Latent") Buildslaves, Up: Configuration + +4.10 Defining Global Properties +=============================== + +The `'properties'' configuration key defines a dictionary of +properties that will be available to all builds started by the +buildmaster: + + c['properties'] = { + 'Widget-version' : '1.2', + 'release-stage' : 'alpha' + } + + +File: buildbot.info, Node: Defining Builders, Next: Defining Status Targets, Prev: Defining Global Properties, Up: Configuration + +4.11 Defining Builders +====================== + +The `c['builders']' key is a list of dictionaries which specify the +Builders. The Buildmaster runs a collection of Builders, each of +which handles a single type of build (e.g. full versus quick), on a +single build slave. A Buildbot which makes sure that the latest code +("HEAD") compiles correctly across four separate architecture will +have four Builders, each performing the same build but on different +slaves (one per platform). + + Each Builder gets a separate column in the waterfall display. In +general, each Builder runs independently (although various kinds of +interlocks can cause one Builder to have an effect on another). + + Each Builder specification dictionary has several required keys: + +`name' + This specifies the Builder's name, which is used in status + reports. + +`slavename' + This specifies which buildslave will be used by this Builder. + `slavename' must appear in the `c['slaves']' list. Each + buildslave can accomodate multiple Builders. + +`slavenames' + If you provide `slavenames' instead of `slavename', you can give + a list of buildslaves which are capable of running this Builder. + If multiple buildslaves are available for any given Builder, you + will have some measure of redundancy: in case one slave goes + offline, the others can still keep the Builder working. In + addition, multiple buildslaves will allow multiple simultaneous + builds for the same Builder, which might be useful if you have a + lot of forced or "try" builds taking place. + + If you use this feature, it is important to make sure that the + buildslaves are all, in fact, capable of running the given + build. The slave hosts should be configured similarly, otherwise + you will spend a lot of time trying (unsuccessfully) to + reproduce a failure that only occurs on some of the buildslaves + and not the others. Different platforms, operating systems, + versions of major programs or libraries, all these things mean + you should use separate Builders. + +`builddir' + This specifies the name of a subdirectory (under the base + directory) in which everything related to this builder will be + placed. On the buildmaster, this holds build status information. + On the buildslave, this is where checkouts, compiles, and tests + are run. + +`factory' + This is a `buildbot.process.factory.BuildFactory' instance which + controls how the build is performed. Full details appear in + their own chapter, *Note Build Process::. Parameters like the + location of the CVS repository and the compile-time options used + for the build are generally provided as arguments to the + factory's constructor. + + + Other optional keys may be set on each Builder: + +`category' + If provided, this is a string that identifies a category for the + builder to be a part of. Status clients can limit themselves to a + subset of the available categories. A common use for this is to + add new builders to your setup (for a new module, or for a new + buildslave) that do not work correctly yet and allow you to + integrate them with the active builders. You can put these new + builders in a test category, make your main status clients + ignore them, and have only private status clients pick them up. + As soon as they work, you can move them over to the active + category. + + + +File: buildbot.info, Node: Defining Status Targets, Next: Debug options, Prev: Defining Builders, Up: Configuration + +4.12 Defining Status Targets +============================ + +The Buildmaster has a variety of ways to present build status to +various users. Each such delivery method is a "Status Target" object +in the configuration's `status' list. To add status targets, you just +append more objects to this list: + + c['status'] = [] + + from buildbot.status import html + c['status'].append(html.Waterfall(http_port=8010)) + + from buildbot.status import mail + m = mail.MailNotifier(fromaddr="buildbot@localhost", + extraRecipients=["builds@lists.example.com"], + sendToInterestedUsers=False) + c['status'].append(m) + + from buildbot.status import words + c['status'].append(words.IRC(host="irc.example.com", nick="bb", + channels=["#example"])) + + Status delivery has its own chapter, *Note Status Delivery::, in +which all the built-in status targets are documented. + + +File: buildbot.info, Node: Debug options, Prev: Defining Status Targets, Up: Configuration + +4.13 Debug options +================== + +If you set `c['debugPassword']', then you can connect to the +buildmaster with the diagnostic tool launched by `buildbot +debugclient MASTER:PORT'. From this tool, you can reload the config +file, manually force builds, and inject changes, which may be useful +for testing your buildmaster without actually commiting changes to +your repository (or before you have the Change Sources set up). The +debug tool uses the same port number as the slaves do: +`c['slavePortnum']', and is authenticated with this password. + + c['debugPassword'] = "debugpassword" + + If you set `c['manhole']' to an instance of one of the classes in +`buildbot.manhole', you can telnet or ssh into the buildmaster and +get an interactive Python shell, which may be useful for debugging +buildbot internals. It is probably only useful for buildbot +developers. It exposes full access to the buildmaster's account +(including the ability to modify and delete files), so it should not +be enabled with a weak or easily guessable password. + + There are three separate `Manhole' classes. Two of them use SSH, +one uses unencrypted telnet. Two of them use a username+password +combination to grant access, one of them uses an SSH-style +`authorized_keys' file which contains a list of ssh public keys. + +`manhole.AuthorizedKeysManhole' + You construct this with the name of a file that contains one SSH + public key per line, just like `~/.ssh/authorized_keys'. If you + provide a non-absolute filename, it will be interpreted relative + to the buildmaster's base directory. + +`manhole.PasswordManhole' + This one accepts SSH connections but asks for a username and + password when authenticating. It accepts only one such pair. + +`manhole.TelnetManhole' + This accepts regular unencrypted telnet connections, and asks + for a username/password pair before providing access. Because + this username/password is transmitted in the clear, and because + Manhole access to the buildmaster is equivalent to granting full + shell privileges to both the buildmaster and all the buildslaves + (and to all accounts which then run code produced by the + buildslaves), it is highly recommended that you use one of the + SSH manholes instead. + + + # some examples: + from buildbot import manhole + c['manhole'] = manhole.AuthorizedKeysManhole(1234, "authorized_keys") + c['manhole'] = manhole.PasswordManhole(1234, "alice", "mysecretpassword") + c['manhole'] = manhole.TelnetManhole(1234, "bob", "snoop_my_password_please") + + The `Manhole' instance can be configured to listen on a specific +port. You may wish to have this listening port bind to the loopback +interface (sometimes known as "lo0", "localhost", or 127.0.0.1) to +restrict access to clients which are running on the same host. + + from buildbot.manhole import PasswordManhole + c['manhole'] = PasswordManhole("tcp:9999:interface=127.0.0.1","admin","passwd") + + To have the `Manhole' listen on all interfaces, use `"tcp:9999"' +or simply 9999. This port specification uses +`twisted.application.strports', so you can make it listen on SSL or +even UNIX-domain sockets if you want. + + Note that using any Manhole requires that the TwistedConch package +be installed, and that you be using Twisted version 2.0 or later. + + The buildmaster's SSH server will use a different host key than the +normal sshd running on a typical unix host. This will cause the ssh +client to complain about a "host key mismatch", because it does not +realize there are two separate servers running on the same host. To +avoid this, use a clause like the following in your `.ssh/config' +file: + + Host remotehost-buildbot + HostName remotehost + HostKeyAlias remotehost-buildbot + Port 9999 + # use 'user' if you use PasswordManhole and your name is not 'admin'. + # if you use AuthorizedKeysManhole, this probably doesn't matter. + User admin + + +File: buildbot.info, Node: Getting Source Code Changes, Next: Build Process, Prev: Configuration, Up: Top + +5 Getting Source Code Changes +***************************** + +The most common way to use the Buildbot is centered around the idea of +`Source Trees': a directory tree filled with source code of some form +which can be compiled and/or tested. Some projects use languages that +don't involve any compilation step: nevertheless there may be a +`build' phase where files are copied or rearranged into a form that +is suitable for installation. Some projects do not have unit tests, +and the Buildbot is merely helping to make sure that the sources can +compile correctly. But in all of these cases, the thing-being-tested +is a single source tree. + + A Version Control System mantains a source tree, and tells the +buildmaster when it changes. The first step of each Build is typically +to acquire a copy of some version of this tree. + + This chapter describes how the Buildbot learns about what Changes +have occurred. For more information on VC systems and Changes, see +*note Version Control Systems::. + +* Menu: + +* Change Sources:: +* Choosing ChangeSources:: +* CVSToys - PBService:: +* Mail-parsing ChangeSources:: +* PBChangeSource:: +* P4Source:: +* BonsaiPoller:: +* SVNPoller:: +* MercurialHook:: +* Bzr Hook:: +* Bzr Poller:: + + +File: buildbot.info, Node: Change Sources, Next: Choosing ChangeSources, Prev: Getting Source Code Changes, Up: Getting Source Code Changes + +5.1 Change Sources +================== + +Each Buildmaster watches a single source tree. Changes can be provided +by a variety of ChangeSource types, however any given project will +typically have only a single ChangeSource active. This section +provides a description of all available ChangeSource types and +explains how to set up each of them. + + There are a variety of ChangeSources available, some of which are +meant to be used in conjunction with other tools to deliver Change +events from the VC repository to the buildmaster. + + * CVSToys This ChangeSource opens a TCP connection from the + buildmaster to a waiting FreshCVS daemon that lives on the + repository machine, and subscribes to hear about Changes. + + * MaildirSource This one watches a local maildir-format inbox for + email sent out by the repository when a change is made. When a + message arrives, it is parsed to create the Change object. A + variety of parsing functions are available to accomodate + different email-sending tools. + + * PBChangeSource This ChangeSource listens on a local TCP socket + for inbound connections from a separate tool. Usually, this tool + would be run on the VC repository machine in a commit hook. It + is expected to connect to the TCP socket and send a Change + message over the network connection. The `buildbot sendchange' + command is one example of a tool that knows how to send these + messages, so you can write a commit script for your VC system + that calls it to deliver the Change. There are other tools in + the contrib/ directory that use the same protocol. + + + As a quick guide, here is a list of VC systems and the +ChangeSources that might be useful with them. All of these +ChangeSources are in the `buildbot.changes' module. + +`CVS' + * freshcvs.FreshCVSSource (connected via TCP to the freshcvs + daemon) + + * mail.FCMaildirSource (watching for email sent by a freshcvs + daemon) + + * mail.BonsaiMaildirSource (watching for email sent by Bonsai) + + * mail.SyncmailMaildirSource (watching for email sent by + syncmail) + + * pb.PBChangeSource (listening for connections from `buildbot + sendchange' run in a loginfo script) + + * pb.PBChangeSource (listening for connections from a + long-running `contrib/viewcvspoll.py' polling process which + examines the ViewCVS database directly + +`SVN' + * pb.PBChangeSource (listening for connections from + `contrib/svn_buildbot.py' run in a postcommit script) + + * pb.PBChangeSource (listening for connections from a + long-running `contrib/svn_watcher.py' or + `contrib/svnpoller.py' polling process + + * mail.SVNCommitEmailMaildirSource (watching for email sent + by commit-email.pl) + + * svnpoller.SVNPoller (polling the SVN repository) + +`Darcs' + * pb.PBChangeSource (listening for connections from + `contrib/darcs_buildbot.py' in a commit script + +`Mercurial' + * pb.PBChangeSource (listening for connections from + `contrib/hg_buildbot.py' run in an 'incoming' hook) + + * pb.PBChangeSource (listening for connections from + `buildbot/changes/hgbuildbot.py' run as an in-process + 'changegroup' hook) + +`Arch/Bazaar' + * pb.PBChangeSource (listening for connections from + `contrib/arch_buildbot.py' run in a commit hook) + +`Bzr (the newer Bazaar)' + * pb.PBChangeSource (listening for connections from + `contrib/bzr_buildbot.py' run in a post-change-branch-tip + or commit hook) + + * `contrib/bzr_buildbot.py''s BzrPoller (polling the Bzr + repository) + +`Git' + * pb.PBChangeSource (listening for connections from + `contrib/git_buildbot.py' run in the post-receive hook) + + + All VC systems can be driven by a PBChangeSource and the `buildbot +sendchange' tool run from some form of commit script. If you write +an email parsing function, they can also all be driven by a suitable +`MaildirSource'. + + +File: buildbot.info, Node: Choosing ChangeSources, Next: CVSToys - PBService, Prev: Change Sources, Up: Getting Source Code Changes + +5.2 Choosing ChangeSources +========================== + +The `master.cfg' configuration file has a dictionary key named +`BuildmasterConfig['change_source']', which holds the active +`IChangeSource' object. The config file will typically create an +object from one of the classes described below and stuff it into this +key. + + Each buildmaster typically has just a single ChangeSource, since +it is only watching a single source tree. But if, for some reason, +you need multiple sources, just set `c['change_source']' to a list of +ChangeSources.. it will accept that too. + + s = FreshCVSSourceNewcred(host="host", port=4519, + user="alice", passwd="secret", + prefix="Twisted") + BuildmasterConfig['change_source'] = [s] + + Each source tree has a nominal `top'. Each Change has a list of +filenames, which are all relative to this top location. The +ChangeSource is responsible for doing whatever is necessary to +accomplish this. Most sources have a `prefix' argument: a partial +pathname which is stripped from the front of all filenames provided to +that `ChangeSource'. Files which are outside this sub-tree are +ignored by the changesource: it does not generate Changes for those +files. + + +File: buildbot.info, Node: CVSToys - PBService, Next: Mail-parsing ChangeSources, Prev: Choosing ChangeSources, Up: Getting Source Code Changes + +5.3 CVSToys - PBService +======================= + +The CVSToys (http://purl.net/net/CVSToys) package provides a server +which runs on the machine that hosts the CVS repository it watches. +It has a variety of ways to distribute commit notifications, and +offers a flexible regexp-based way to filter out uninteresting +changes. One of the notification options is named `PBService' and +works by listening on a TCP port for clients. These clients subscribe +to hear about commit notifications. + + The buildmaster has a CVSToys-compatible `PBService' client built +in. There are two versions of it, one for old versions of CVSToys +(1.0.9 and earlier) which used the `oldcred' authentication +framework, and one for newer versions (1.0.10 and later) which use +`newcred'. Both are classes in the `buildbot.changes.freshcvs' +package. + + `FreshCVSSourceNewcred' objects are created with the following +parameters: + +``host' and `port'' + these specify where the CVSToys server can be reached + +``user' and `passwd'' + these specify the login information for the CVSToys server + (`freshcvs'). These must match the server's values, which are + defined in the `freshCfg' configuration file (which lives in the + CVSROOT directory of the repository). + +``prefix'' + this is the prefix to be found and stripped from filenames + delivered by the CVSToys server. Most projects live in + sub-directories of the main repository, as siblings of the + CVSROOT sub-directory, so typically this prefix is set to that + top sub-directory name. + + +Example +======= + +To set up the freshCVS server, add a statement like the following to +your `freshCfg' file: + + pb = ConfigurationSet([ + (None, None, None, PBService(userpass=('foo', 'bar'), port=4519)), + ]) + + This will announce all changes to a client which connects to port +4519 using a username of 'foo' and a password of 'bar'. + + Then add a clause like this to your buildmaster's `master.cfg': + + BuildmasterConfig['change_source'] = FreshCVSSource("cvs.example.com", 4519, + "foo", "bar", + prefix="glib/") + + where "cvs.example.com" is the host that is running the FreshCVS +daemon, and "glib" is the top-level directory (relative to the +repository's root) where all your source code lives. Most projects +keep one or more projects in the same repository (along with CVSROOT/ +to hold admin files like loginfo and freshCfg); the prefix= argument +tells the buildmaster to ignore everything outside that directory, +and to strip that common prefix from all pathnames it handles. + + +File: buildbot.info, Node: Mail-parsing ChangeSources, Next: PBChangeSource, Prev: CVSToys - PBService, Up: Getting Source Code Changes + +5.4 Mail-parsing ChangeSources +============================== + +Many projects publish information about changes to their source tree +by sending an email message out to a mailing list, frequently named +PROJECT-commits or PROJECT-changes. Each message usually contains a +description of the change (who made the change, which files were +affected) and sometimes a copy of the diff. Humans can subscribe to +this list to stay informed about what's happening to the source tree. + + The Buildbot can also be subscribed to a -commits mailing list, and +can trigger builds in response to Changes that it hears about. The +buildmaster admin needs to arrange for these email messages to arrive +in a place where the buildmaster can find them, and configure the +buildmaster to parse the messages correctly. Once that is in place, +the email parser will create Change objects and deliver them to the +Schedulers (see *note Change Sources and Schedulers::) just like any +other ChangeSource. + + There are two components to setting up an email-based ChangeSource. +The first is to route the email messages to the buildmaster, which is +done by dropping them into a "maildir". The second is to actually +parse the messages, which is highly dependent upon the tool that was +used to create them. Each VC system has a collection of favorite +change-emailing tools, and each has a slightly different format, so +each has a different parsing function. There is a separate +ChangeSource variant for each parsing function. + + Once you've chosen a maildir location and a parsing function, +create the change source and put it in `c['change_source']': + + from buildbot.changes.mail import SyncmailMaildirSource + c['change_source'] = SyncmailMaildirSource("~/maildir-buildbot", + prefix="/trunk/") + +* Menu: + +* Subscribing the Buildmaster:: +* Using Maildirs:: +* Parsing Email Change Messages:: + + +File: buildbot.info, Node: Subscribing the Buildmaster, Next: Using Maildirs, Prev: Mail-parsing ChangeSources, Up: Mail-parsing ChangeSources + +5.4.1 Subscribing the Buildmaster +--------------------------------- + +The recommended way to install the buildbot is to create a dedicated +account for the buildmaster. If you do this, the account will probably +have a distinct email address (perhaps <buildmaster@example.org>). +Then just arrange for this account's email to be delivered to a +suitable maildir (described in the next section). + + If the buildbot does not have its own account, "extension +addresses" can be used to distinguish between email intended for the +buildmaster and email intended for the rest of the account. In most +modern MTAs, the e.g. `foo@example.org' account has control over +every email address at example.org which begins with "foo", such that +email addressed to <account-foo@example.org> can be delivered to a +different destination than <account-bar@example.org>. qmail does this +by using separate .qmail files for the two destinations (`.qmail-foo' +and `.qmail-bar', with `.qmail' controlling the base address and +`.qmail-default' controlling all other extensions). Other MTAs have +similar mechanisms. + + Thus you can assign an extension address like +<foo-buildmaster@example.org> to the buildmaster, and retain +<foo@example.org> for your own use. + + +File: buildbot.info, Node: Using Maildirs, Next: Parsing Email Change Messages, Prev: Subscribing the Buildmaster, Up: Mail-parsing ChangeSources + +5.4.2 Using Maildirs +-------------------- + +A "maildir" is a simple directory structure originally developed for +qmail that allows safe atomic update without locking. Create a base +directory with three subdirectories: "new", "tmp", and "cur". When +messages arrive, they are put into a uniquely-named file (using pids, +timestamps, and random numbers) in "tmp". When the file is complete, +it is atomically renamed into "new". Eventually the buildmaster +notices the file in "new", reads and parses the contents, then moves +it into "cur". A cronjob can be used to delete files in "cur" at +leisure. + + Maildirs are frequently created with the `maildirmake' tool, but a +simple `mkdir -p ~/MAILDIR/{cur,new,tmp}' is pretty much equivalent. + + Many modern MTAs can deliver directly to maildirs. The usual +.forward or .procmailrc syntax is to name the base directory with a +trailing slash, so something like `~/MAILDIR/' . qmail and postfix are +maildir-capable MTAs, and procmail is a maildir-capable MDA (Mail +Delivery Agent). + + For MTAs which cannot put files into maildirs directly, the +"safecat" tool can be executed from a .forward file to accomplish the +same thing. + + The Buildmaster uses the linux DNotify facility to receive +immediate notification when the maildir's "new" directory has +changed. When this facility is not available, it polls the directory +for new messages, every 10 seconds by default. + + +File: buildbot.info, Node: Parsing Email Change Messages, Prev: Using Maildirs, Up: Mail-parsing ChangeSources + +5.4.3 Parsing Email Change Messages +----------------------------------- + +The second component to setting up an email-based ChangeSource is to +parse the actual notices. This is highly dependent upon the VC system +and commit script in use. + + A couple of common tools used to create these change emails are: + +`CVS' + + `CVSToys MailNotifier' + *note FCMaildirSource:: + + `Bonsai notification' + *note BonsaiMaildirSource:: + + `syncmail' + *note SyncmailMaildirSource:: + +`SVN' + + `svnmailer' + http://opensource.perlig.de/en/svnmailer/ + + `commit-email.pl' + *note SVNCommitEmailMaildirSource:: + +`Mercurial' + + `NotifyExtension' + http://www.selenic.com/mercurial/wiki/index.cgi/NotifyExtension + +`Git' + + `post-receive-email' + http://git.kernel.org/?p=git/git.git;a=blob;f=contrib/hooks/post-receive-email;hb=HEAD + + + The following sections describe the parsers available for each of +these tools. + + Most of these parsers accept a `prefix=' argument, which is used +to limit the set of files that the buildmaster pays attention to. This +is most useful for systems like CVS and SVN which put multiple +projects in a single repository (or use repository names to indicate +branches). Each filename that appears in the email is tested against +the prefix: if the filename does not start with the prefix, the file +is ignored. If the filename _does_ start with the prefix, that prefix +is stripped from the filename before any further processing is done. +Thus the prefix usually ends with a slash. + +* Menu: + +* FCMaildirSource:: +* SyncmailMaildirSource:: +* BonsaiMaildirSource:: +* SVNCommitEmailMaildirSource:: + + +File: buildbot.info, Node: FCMaildirSource, Next: SyncmailMaildirSource, Prev: Parsing Email Change Messages, Up: Parsing Email Change Messages + +5.4.3.1 FCMaildirSource +....................... + +http://twistedmatrix.com/users/acapnotic/wares/code/CVSToys/ + + This parser works with the CVSToys `MailNotification' action, +which will send email to a list of recipients for each commit. This +tends to work better than using `/bin/mail' from within the +CVSROOT/loginfo file directly, as CVSToys will batch together all +files changed during the same CVS invocation, and can provide more +information (like creating a ViewCVS URL for each file changed). + + The Buildbot's `FCMaildirSource' knows for to parse these CVSToys +messages and turn them into Change objects. It can be given two +parameters: the directory name of the maildir root, and the prefix to +strip. + + from buildbot.changes.mail import FCMaildirSource + c['change_source'] = FCMaildirSource("~/maildir-buildbot") + + +File: buildbot.info, Node: SyncmailMaildirSource, Next: BonsaiMaildirSource, Prev: FCMaildirSource, Up: Parsing Email Change Messages + +5.4.3.2 SyncmailMaildirSource +............................. + +http://sourceforge.net/projects/cvs-syncmail + + `SyncmailMaildirSource' knows how to parse the message format used +by the CVS "syncmail" script. + + from buildbot.changes.mail import SyncmailMaildirSource + c['change_source'] = SyncmailMaildirSource("~/maildir-buildbot") + + +File: buildbot.info, Node: BonsaiMaildirSource, Next: SVNCommitEmailMaildirSource, Prev: SyncmailMaildirSource, Up: Parsing Email Change Messages + +5.4.3.3 BonsaiMaildirSource +........................... + +http://www.mozilla.org/bonsai.html + + `BonsaiMaildirSource' parses messages sent out by Bonsai, the CVS +tree-management system built by Mozilla. + + from buildbot.changes.mail import BonsaiMaildirSource + c['change_source'] = BonsaiMaildirSource("~/maildir-buildbot") + + +File: buildbot.info, Node: SVNCommitEmailMaildirSource, Prev: BonsaiMaildirSource, Up: Parsing Email Change Messages + +5.4.3.4 SVNCommitEmailMaildirSource +................................... + +`SVNCommitEmailMaildirSource' parses message sent out by the +`commit-email.pl' script, which is included in the Subversion +distribution. + + It does not currently handle branches: all of the Change objects +that it creates will be associated with the default (i.e. trunk) +branch. + + from buildbot.changes.mail import SVNCommitEmailMaildirSource + c['change_source'] = SVNCommitEmailMaildirSource("~/maildir-buildbot") + + +File: buildbot.info, Node: PBChangeSource, Next: P4Source, Prev: Mail-parsing ChangeSources, Up: Getting Source Code Changes + +5.5 PBChangeSource +================== + +The last kind of ChangeSource actually listens on a TCP port for +clients to connect and push change notices _into_ the Buildmaster. +This is used by the built-in `buildbot sendchange' notification tool, +as well as the VC-specific `contrib/svn_buildbot.py', +`contrib/arch_buildbot.py', `contrib/hg_buildbot.py' tools, and the +`buildbot.changes.hgbuildbot' hook. These tools are run by the +repository (in a commit hook script), and connect to the buildmaster +directly each time a file is comitted. This is also useful for +creating new kinds of change sources that work on a `push' model +instead of some kind of subscription scheme, for example a script +which is run out of an email .forward file. + + This ChangeSource can be configured to listen on its own TCP port, +or it can share the port that the buildmaster is already using for the +buildslaves to connect. (This is possible because the +`PBChangeSource' uses the same protocol as the buildslaves, and they +can be distinguished by the `username' attribute used when the +initial connection is established). It might be useful to have it +listen on a different port if, for example, you wanted to establish +different firewall rules for that port. You could allow only the SVN +repository machine access to the `PBChangeSource' port, while +allowing only the buildslave machines access to the slave port. Or you +could just expose one port and run everything over it. _Note: this +feature is not yet implemented, the PBChangeSource will always share +the slave port and will always have a `user' name of `change', and a +passwd of `changepw'. These limitations will be removed in the +future._. + + The `PBChangeSource' is created with the following arguments. All +are optional. + +``port'' + which port to listen on. If `None' (which is the default), it + shares the port used for buildslave connections. _Not + Implemented, always set to `None'_. + +``user' and `passwd'' + The user/passwd account information that the client program must + use to connect. Defaults to `change' and `changepw'. _Not + Implemented, `user' is currently always set to `change', + `passwd' is always set to `changepw'_. + +``prefix'' + The prefix to be found and stripped from filenames delivered + over the connection. Any filenames which do not start with this + prefix will be removed. If all the filenames in a given Change + are removed, the that whole Change will be dropped. This string + should probably end with a directory separator. + + This is useful for changes coming from version control systems + that represent branches as parent directories within the + repository (like SVN and Perforce). Use a prefix of 'trunk/' or + 'project/branches/foobranch/' to only follow one branch and to + get correct tree-relative filenames. Without a prefix, the + PBChangeSource will probably deliver Changes with filenames like + `trunk/foo.c' instead of just `foo.c'. Of course this also + depends upon the tool sending the Changes in (like `buildbot + sendchange') and what filenames it is delivering: that tool may + be filtering and stripping prefixes at the sending end. + + + +File: buildbot.info, Node: P4Source, Next: BonsaiPoller, Prev: PBChangeSource, Up: Getting Source Code Changes + +5.6 P4Source +============ + +The `P4Source' periodically polls a Perforce +(http://www.perforce.com/) depot for changes. It accepts the +following arguments: + +``p4base'' + The base depot path to watch, without the trailing '/...'. + +``p4port'' + The Perforce server to connect to (as host:port). + +``p4user'' + The Perforce user. + +``p4passwd'' + The Perforce password. + +``p4bin'' + An optional string parameter. Specify the location of the + perforce command line binary (p4). You only need to do this if + the perforce binary is not in the path of the buildbot user. + Defaults to "p4". + +``split_file'' + A function that maps a pathname, without the leading `p4base', + to a (branch, filename) tuple. The default just returns (None, + branchfile), which effectively disables branch support. You + should supply a function which understands your repository + structure. + +``pollinterval'' + How often to poll, in seconds. Defaults to 600 (10 minutes). + +``histmax'' + The maximum number of changes to inspect at a time. If more than + this number occur since the last poll, older changes will be + silently ignored. + +Example +======= + +This configuration uses the `P4PORT', `P4USER', and `P4PASSWD' +specified in the buildmaster's environment. It watches a project in +which the branch name is simply the next path component, and the file +is all path components after. + + import buildbot.changes.p4poller + s = p4poller.P4Source(p4base='//depot/project/', + split_file=lambda branchfile: branchfile.split('/',1), + ) + c['change_source'] = s + + +File: buildbot.info, Node: BonsaiPoller, Next: SVNPoller, Prev: P4Source, Up: Getting Source Code Changes + +5.7 BonsaiPoller +================ + +The `BonsaiPoller' periodically polls a Bonsai server. This is a CGI +script accessed through a web server that provides information about +a CVS tree, for example the Mozilla bonsai server at +`http://bonsai.mozilla.org'. Bonsai servers are usable by both humans +and machines. In this case, the buildbot's change source forms a +query which asks about any files in the specified branch which have +changed since the last query. + + Please take a look at the BonsaiPoller docstring for details about +the arguments it accepts. + + +File: buildbot.info, Node: SVNPoller, Next: MercurialHook, Prev: BonsaiPoller, Up: Getting Source Code Changes + +5.8 SVNPoller +============= + +The `buildbot.changes.svnpoller.SVNPoller' is a ChangeSource which +periodically polls a Subversion (http://subversion.tigris.org/) +repository for new revisions, by running the `svn log' command in a +subshell. It can watch a single branch or multiple branches. + + `SVNPoller' accepts the following arguments: + +`svnurl' + The base URL path to watch, like + `svn://svn.twistedmatrix.com/svn/Twisted/trunk', or + `http://divmod.org/svn/Divmod/', or even + `file:///home/svn/Repository/ProjectA/branches/1.5/'. This must + include the access scheme, the location of the repository (both + the hostname for remote ones, and any additional directory names + necessary to get to the repository), and the sub-path within the + repository's virtual filesystem for the project and branch of + interest. + + The `SVNPoller' will only pay attention to files inside the + subdirectory specified by the complete svnurl. + +`split_file' + A function to convert pathnames into (branch, relative_pathname) + tuples. Use this to explain your repository's branch-naming + policy to `SVNPoller'. This function must accept a single string + and return a two-entry tuple. There are a few utility functions + in `buildbot.changes.svnpoller' that can be used as a + `split_file' function, see below for details. + + The default value always returns (None, path), which indicates + that all files are on the trunk. + + Subclasses of `SVNPoller' can override the `split_file' method + instead of using the `split_file=' argument. + +`svnuser' + An optional string parameter. If set, the `--user' argument will + be added to all `svn' commands. Use this if you have to + authenticate to the svn server before you can do `svn info' or + `svn log' commands. + +`svnpasswd' + Like `svnuser', this will cause a `--password' argument to be + passed to all svn commands. + +`pollinterval' + How often to poll, in seconds. Defaults to 600 (checking once + every 10 minutes). Lower this if you want the buildbot to notice + changes faster, raise it if you want to reduce the network and + CPU load on your svn server. Please be considerate of public SVN + repositories by using a large interval when polling them. + +`histmax' + The maximum number of changes to inspect at a time. Every + POLLINTERVAL seconds, the `SVNPoller' asks for the last HISTMAX + changes and looks through them for any ones it does not already + know about. If more than HISTMAX revisions have been committed + since the last poll, older changes will be silently ignored. + Larger values of histmax will cause more time and memory to be + consumed on each poll attempt. `histmax' defaults to 100. + +`svnbin' + This controls the `svn' executable to use. If subversion is + installed in a weird place on your system (outside of the + buildmaster's `$PATH'), use this to tell `SVNPoller' where to + find it. The default value of "svn" will almost always be + sufficient. + + +Branches +======== + +Each source file that is tracked by a Subversion repository has a +fully-qualified SVN URL in the following form: +(REPOURL)(PROJECT-plus-BRANCH)(FILEPATH). When you create the +`SVNPoller', you give it a `svnurl' value that includes all of the +REPOURL and possibly some portion of the PROJECT-plus-BRANCH string. +The `SVNPoller' is responsible for producing Changes that contain a +branch name and a FILEPATH (which is relative to the top of a +checked-out tree). The details of how these strings are split up +depend upon how your repository names its branches. + +PROJECT/BRANCHNAME/FILEPATH repositories +---------------------------------------- + +One common layout is to have all the various projects that share a +repository get a single top-level directory each. Then under a given +project's directory, you get two subdirectories, one named "trunk" +and another named "branches". Under "branches" you have a bunch of +other directories, one per branch, with names like "1.5.x" and +"testing". It is also common to see directories like "tags" and +"releases" next to "branches" and "trunk". + + For example, the Twisted project has a subversion server on +"svn.twistedmatrix.com" that hosts several sub-projects. The +repository is available through a SCHEME of "svn:". The primary +sub-project is Twisted, of course, with a repository root of +"svn://svn.twistedmatrix.com/svn/Twisted". Another sub-project is +Informant, with a root of +"svn://svn.twistedmatrix.com/svn/Informant", etc. Inside any +checked-out Twisted tree, there is a file named bin/trial (which is +used to run unit test suites). + + The trunk for Twisted is in +"svn://svn.twistedmatrix.com/svn/Twisted/trunk", and the +fully-qualified SVN URL for the trunk version of `trial' would be +"svn://svn.twistedmatrix.com/svn/Twisted/trunk/bin/trial". The same +SVNURL for that file on a branch named "1.5.x" would be +"svn://svn.twistedmatrix.com/svn/Twisted/branches/1.5.x/bin/trial". + + To set up a `SVNPoller' that watches the Twisted trunk (and +nothing else), we would use the following: + + from buildbot.changes.svnpoller import SVNPoller + c['change_source'] = SVNPoller("svn://svn.twistedmatrix.com/svn/Twisted/trunk") + + In this case, every Change that our `SVNPoller' produces will have +`.branch=None', to indicate that the Change is on the trunk. No +other sub-projects or branches will be tracked. + + If we want our ChangeSource to follow multiple branches, we have +to do two things. First we have to change our `svnurl=' argument to +watch more than just ".../Twisted/trunk". We will set it to +".../Twisted" so that we'll see both the trunk and all the branches. +Second, we have to tell `SVNPoller' how to split the +(PROJECT-plus-BRANCH)(FILEPATH) strings it gets from the repository +out into (BRANCH) and (FILEPATH) pairs. + + We do the latter by providing a "split_file" function. This +function is responsible for splitting something like +"branches/1.5.x/bin/trial" into `branch'="branches/1.5.x" and +`filepath'="bin/trial". This function is always given a string that +names a file relative to the subdirectory pointed to by the +`SVNPoller''s `svnurl=' argument. It is expected to return a +(BRANCHNAME, FILEPATH) tuple (in which FILEPATH is relative to the +branch indicated), or None to indicate that the file is outside any +project of interest. + + (note that we want to see "branches/1.5.x" rather than just +"1.5.x" because when we perform the SVN checkout, we will probably +append the branch name to the baseURL, which requires that we keep the +"branches" component in there. Other VC schemes use a different +approach towards branches and may not require this artifact.) + + If your repository uses this same PROJECT/BRANCH/FILEPATH naming +scheme, the following function will work: + + def split_file_branches(path): + pieces = path.split('/') + if pieces[0] == 'trunk': + return (None, '/'.join(pieces[1:])) + elif pieces[0] == 'branches': + return ('/'.join(pieces[0:2]), + '/'.join(pieces[2:])) + else: + return None + + This function is provided as +`buildbot.changes.svnpoller.split_file_branches' for your +convenience. So to have our Twisted-watching `SVNPoller' follow +multiple branches, we would use this: + + from buildbot.changes.svnpoller import SVNPoller, split_file_branches + c['change_source'] = SVNPoller("svn://svn.twistedmatrix.com/svn/Twisted", + split_file=split_file_branches) + + Changes for all sorts of branches (with names like +"branches/1.5.x", and None to indicate the trunk) will be delivered +to the Schedulers. Each Scheduler is then free to use or ignore each +branch as it sees fit. + +BRANCHNAME/PROJECT/FILEPATH repositories +---------------------------------------- + +Another common way to organize a Subversion repository is to put the +branch name at the top, and the projects underneath. This is +especially frequent when there are a number of related sub-projects +that all get released in a group. + + For example, Divmod.org hosts a project named "Nevow" as well as +one named "Quotient". In a checked-out Nevow tree there is a directory +named "formless" that contains a python source file named +"webform.py". This repository is accessible via webdav (and thus uses +an "http:" scheme) through the divmod.org hostname. There are many +branches in this repository, and they use a (BRANCHNAME)/(PROJECT) +naming policy. + + The fully-qualified SVN URL for the trunk version of webform.py is +`http://divmod.org/svn/Divmod/trunk/Nevow/formless/webform.py'. You +can do an `svn co' with that URL and get a copy of the latest +version. The 1.5.x branch version of this file would have a URL of +`http://divmod.org/svn/Divmod/branches/1.5.x/Nevow/formless/webform.py'. +The whole Nevow trunk would be checked out with +`http://divmod.org/svn/Divmod/trunk/Nevow', while the Quotient trunk +would be checked out using +`http://divmod.org/svn/Divmod/trunk/Quotient'. + + Now suppose we want to have an `SVNPoller' that only cares about +the Nevow trunk. This case looks just like the PROJECT/BRANCH layout +described earlier: + + from buildbot.changes.svnpoller import SVNPoller + c['change_source'] = SVNPoller("http://divmod.org/svn/Divmod/trunk/Nevow") + + But what happens when we want to track multiple Nevow branches? We +have to point our `svnurl=' high enough to see all those branches, +but we also don't want to include Quotient changes (since we're only +building Nevow). To accomplish this, we must rely upon the +`split_file' function to help us tell the difference between files +that belong to Nevow and those that belong to Quotient, as well as +figuring out which branch each one is on. + + from buildbot.changes.svnpoller import SVNPoller + c['change_source'] = SVNPoller("http://divmod.org/svn/Divmod", + split_file=my_file_splitter) + + The `my_file_splitter' function will be called with +repository-relative pathnames like: + +`trunk/Nevow/formless/webform.py' + This is a Nevow file, on the trunk. We want the Change that + includes this to see a filename of `formless/webform.py"', and a + branch of None + +`branches/1.5.x/Nevow/formless/webform.py' + This is a Nevow file, on a branch. We want to get + branch="branches/1.5.x" and filename="formless/webform.py". + +`trunk/Quotient/setup.py' + This is a Quotient file, so we want to ignore it by having + `my_file_splitter' return None. + +`branches/1.5.x/Quotient/setup.py' + This is also a Quotient file, which should be ignored. + + The following definition for `my_file_splitter' will do the job: + + def my_file_splitter(path): + pieces = path.split('/') + if pieces[0] == 'trunk': + branch = None + pieces.pop(0) # remove 'trunk' + elif pieces[0] == 'branches': + pieces.pop(0) # remove 'branches' + # grab branch name + branch = 'branches/' + pieces.pop(0) + else: + return None # something weird + projectname = pieces.pop(0) + if projectname != 'Nevow': + return None # wrong project + return (branch, '/'.join(pieces)) + + +File: buildbot.info, Node: MercurialHook, Next: Bzr Hook, Prev: SVNPoller, Up: Getting Source Code Changes + +5.9 MercurialHook +================= + +Since Mercurial is written in python, the hook script can invoke +Buildbot's `sendchange' function directly, rather than having to +spawn an external process. This function delivers the same sort of +changes as `buildbot sendchange' and the various hook scripts in +contrib/, so you'll need to add a `pb.PBChangeSource' to your +buildmaster to receive these changes. + + To set this up, first choose a Mercurial repository that represents +your central "official" source tree. This will be the same repository +that your buildslaves will eventually pull from. Install Buildbot on +the machine that hosts this repository, using the same version of +python as Mercurial is using (so that the Mercurial hook can import +code from buildbot). Then add the following to the `.hg/hgrc' file in +that repository, replacing the buildmaster hostname/portnumber as +appropriate for your buildbot: + + [hooks] + changegroup.buildbot = python:buildbot.changes.hgbuildbot.hook + + [hgbuildbot] + master = buildmaster.example.org:9987 + + (Note that Mercurial lets you define multiple `changegroup' hooks +by giving them distinct names, like `changegroup.foo' and +`changegroup.bar', which is why we use `changegroup.buildbot' in this +example. There is nothing magical about the "buildbot" suffix in the +hook name. The `[hgbuildbot]' section _is_ special, however, as it is +the only section that the buildbot hook pays attention to.) + + Also note that this runs as a `changegroup' hook, rather than as +an `incoming' hook. The `changegroup' hook is run with multiple +revisions at a time (say, if multiple revisions are being pushed to +this repository in a single `hg push' command), whereas the +`incoming' hook is run with just one revision at a time. The +`hgbuildbot.hook' function will only work with the `changegroup' hook. + + The `[hgbuildbot]' section has two other parameters that you might +specify, both of which control the name of the branch that is +attached to the changes coming from this hook. + + One common branch naming policy for Mercurial repositories is to +use it just like Darcs: each branch goes into a separate repository, +and all the branches for a single project share a common parent +directory. For example, you might have `/var/repos/PROJECT/trunk/' +and `/var/repos/PROJECT/release'. To use this style, use the +`branchtype = dirname' setting, which simply uses the last component +of the repository's enclosing directory as the branch name: + + [hgbuildbot] + master = buildmaster.example.org:9987 + branchtype = dirname + + Another approach is to use Mercurial's built-in branches (the kind +created with `hg branch' and listed with `hg branches'). This feature +associates persistent names with particular lines of descent within a +single repository. (note that the buildbot `source.Mercurial' +checkout step does not yet support this kind of branch). To have the +commit hook deliver this sort of branch name with the Change object, +use `branchtype = inrepo': + + [hgbuildbot] + master = buildmaster.example.org:9987 + branchtype = inrepo + + Finally, if you want to simply specify the branchname directly, for +all changes, use `branch = BRANCHNAME'. This overrides `branchtype': + + [hgbuildbot] + master = buildmaster.example.org:9987 + branch = trunk + + If you use `branch=' like this, you'll need to put a separate +.hgrc in each repository. If you use `branchtype=', you may be able +to use the same .hgrc for all your repositories, stored in `~/.hgrc' +or `/etc/mercurial/hgrc'. + + +File: buildbot.info, Node: Bzr Hook, Next: Bzr Poller, Prev: MercurialHook, Up: Getting Source Code Changes + +5.10 Bzr Hook +============= + +Bzr is also written in Python, and the Bzr hook depends on Twisted to +send the changes. + + To install, put `contrib/bzr_buildbot.py' in one of your plugins +locations a bzr plugins directory (e.g., `~/.bazaar/plugins'). Then, +in one of your bazaar conf files (e.g., `~/.bazaar/locations.conf'), +set the location you want to connect with buildbot with these keys: + +`buildbot_on' + one of 'commit', 'push, or 'change'. Turns the plugin on to + report changes via commit, changes via push, or any changes to + the trunk. 'change' is recommended. + +`buildbot_server' + (required to send to a buildbot master) the URL of the buildbot + master to which you will connect (as of this writing, the same + server and port to which slaves connect). + +`buildbot_port' + (optional, defaults to 9989) the port of the buildbot master to + which you will connect (as of this writing, the same server and + port to which slaves connect) + +`buildbot_pqm' + (optional, defaults to not pqm) Normally, the user that commits + the revision is the user that is responsible for the change. + When run in a pqm (Patch Queue Manager, see + https://launchpad.net/pqm) environment, the user that commits is + the Patch Queue Manager, and the user that committed the + *parent* revision is responsible for the change. To turn on the + pqm mode, set this value to any of (case-insensitive) "Yes", + "Y", "True", or "T". + +`buildbot_dry_run' + (optional, defaults to not a dry run) Normally, the post-commit + hook will attempt to communicate with the configured buildbot + server and port. If this parameter is included and any of + (case-insensitive) "Yes", "Y", "True", or "T", then the hook + will simply print what it would have sent, but not attempt to + contact the buildbot master. + +`buildbot_send_branch_name' + (optional, defaults to not sending the branch name) If your + buildbot's bzr source build step uses a repourl, do *not* turn + this on. If your buildbot's bzr build step uses a baseURL, then + you may set this value to any of (case-insensitive) "Yes", "Y", + "True", or "T" to have the buildbot master append the branch + name to the baseURL. + + + When buildbot no longer has a hardcoded password, it will be a +configuration option here as well. + + Here's a simple example that you might have in your +`~/.bazaar/locations.conf'. + + [chroot-*:///var/local/myrepo/mybranch] + buildbot_on = change + buildbot_server = localhost + + +File: buildbot.info, Node: Bzr Poller, Prev: Bzr Hook, Up: Getting Source Code Changes + +5.11 Bzr Poller +=============== + +If you cannot insert a Bzr hook in the server, you can use the Bzr +Poller. To use, put `contrib/bzr_buildbot.py' somewhere that your +buildbot configuration can import it. Even putting it in the same +directory as the master.cfg should work. Install the poller in the +buildbot configuration as with any other change source. Minimally, +provide a URL that you want to poll (bzr://, bzr+ssh://, or lp:), +though make sure the buildbot user has necessary privileges. You may +also want to specify these optional values. + +`poll_interval' + The number of seconds to wait between polls. Defaults to 10 + minutes. + +`branch_name' + Any value to be used as the branch name. Defaults to None, or + specify a string, or specify the constants from + `bzr_buildbot.py' SHORT or FULL to get the short branch name or + full branch address. + +`blame_merge_author' + normally, the user that commits the revision is the user that is + responsible for the change. When run in a pqm (Patch Queue + Manager, see https://launchpad.net/pqm) environment, the user + that commits is the Patch Queue Manager, and the user that + committed the merged, *parent* revision is responsible for the + change. set this value to True if this is pointed against a + PQM-managed branch. + + +File: buildbot.info, Node: Build Process, Next: Status Delivery, Prev: Getting Source Code Changes, Up: Top + +6 Build Process +*************** + +A `Build' object is responsible for actually performing a build. It +gets access to a remote `SlaveBuilder' where it may run commands, and +a `BuildStatus' object where it must emit status events. The `Build' +is created by the Builder's `BuildFactory'. + + The default `Build' class is made up of a fixed sequence of +`BuildSteps', executed one after another until all are complete (or +one of them indicates that the build should be halted early). The +default `BuildFactory' creates instances of this `Build' class with a +list of `BuildSteps', so the basic way to configure the build is to +provide a list of `BuildSteps' to your `BuildFactory'. + + More complicated `Build' subclasses can make other decisions: +execute some steps only if certain files were changed, or if certain +previous steps passed or failed. The base class has been written to +allow users to express basic control flow without writing code, but +you can always subclass and customize to achieve more specialized +behavior. + +* Menu: + +* Build Steps:: +* Interlocks:: +* Build Factories:: + + +File: buildbot.info, Node: Build Steps, Next: Interlocks, Prev: Build Process, Up: Build Process + +6.1 Build Steps +=============== + +`BuildStep's are usually specified in the buildmaster's configuration +file, in a list that goes into the `BuildFactory'. The `BuildStep' +instances in this list are used as templates to construct new +independent copies for each build (so that state can be kept on the +`BuildStep' in one build without affecting a later build). Each +`BuildFactory' can be created with a list of steps, or the factory +can be created empty and then steps added to it using the `addStep' +method: + + from buildbot.steps import source, shell + from buildbot.process import factory + + f = factory.BuildFactory() + f.addStep(source.SVN(svnurl="http://svn.example.org/Trunk/")) + f.addStep(shell.ShellCommand(command=["make", "all"])) + f.addStep(shell.ShellCommand(command=["make", "test"])) + + In earlier versions (0.7.5 and older), these steps were specified +with a tuple of (step_class, keyword_arguments). Steps can still be +specified this way, but the preferred form is to pass actual +`BuildStep' instances to `addStep', because that gives the +`BuildStep' class a chance to do some validation on the arguments. + + If you have a common set of steps which are used in several +factories, the `addSteps' method may be handy. It takes an iterable +of `BuildStep' instances. + + setup_steps = [ + source.SVN(svnurl="http://svn.example.org/Trunk/") + shell.ShellCommand(command="./setup") + ] + quick = factory.BuildFactory() + quick.addSteps(setup_steps) + quick.addStep(shell.shellCommand(command="make quick")) + + The rest of this section lists all the standard BuildStep objects +available for use in a Build, and the parameters which can be used to +control each. + +* Menu: + +* Common Parameters:: +* Using Build Properties:: +* Source Checkout:: +* ShellCommand:: +* Simple ShellCommand Subclasses:: +* Python BuildSteps:: +* Transferring Files:: +* Steps That Run on the Master:: +* Triggering Schedulers:: +* Writing New BuildSteps:: + + +File: buildbot.info, Node: Common Parameters, Next: Using Build Properties, Prev: Build Steps, Up: Build Steps + +6.1.1 Common Parameters +----------------------- + +The standard `Build' runs a series of `BuildStep's in order, only +stopping when it runs out of steps or if one of them requests that +the build be halted. It collects status information from each one to +create an overall build status (of SUCCESS, WARNINGS, or FAILURE). + + All BuildSteps accept some common parameters. Some of these control +how their individual status affects the overall build. Others are used +to specify which `Locks' (see *note Interlocks::) should be acquired +before allowing the step to run. + + Arguments common to all `BuildStep' subclasses: + +`name' + the name used to describe the step on the status display. It is + also used to give a name to any LogFiles created by this step. + +`haltOnFailure' + if True, a FAILURE of this build step will cause the build to + halt immediately. Steps with `alwaysRun=True' are still run. + Generally speaking, haltOnFailure implies flunkOnFailure (the + default for most BuildSteps). In some cases, particularly series + of tests, it makes sense to haltOnFailure if something fails + early on but not flunkOnFailure. This can be achieved with + haltOnFailure=True, flunkOnFailure=False. + +`flunkOnWarnings' + when True, a WARNINGS or FAILURE of this build step will mark the + overall build as FAILURE. The remaining steps will still be + executed. + +`flunkOnFailure' + when True, a FAILURE of this build step will mark the overall + build as a FAILURE. The remaining steps will still be executed. + +`warnOnWarnings' + when True, a WARNINGS or FAILURE of this build step will mark the + overall build as having WARNINGS. The remaining steps will still + be executed. + +`warnOnFailure' + when True, a FAILURE of this build step will mark the overall + build as having WARNINGS. The remaining steps will still be + executed. + +`alwaysRun' + if True, this build step will always be run, even if a previous + buildstep with `haltOnFailure=True' has failed. + +`locks' + a list of Locks (instances of `buildbot.locks.SlaveLock' or + `buildbot.locks.MasterLock') that should be acquired before + starting this Step. The Locks will be released when the step is + complete. Note that this is a list of actual Lock instances, not + names. Also note that all Locks must have unique names. + + + +File: buildbot.info, Node: Using Build Properties, Next: Source Checkout, Prev: Common Parameters, Up: Build Steps + +6.1.2 Using Build Properties +---------------------------- + +Build properties are a generalized way to provide configuration +information to build steps; see *note Build Properties::. + + Some build properties are inherited from external sources - global +properties, schedulers, or buildslaves. Some build properties are +set when the build starts, such as the SourceStamp information. Other +properties can be set by BuildSteps as they run, for example the +various Source steps will set the `got_revision' property to the +source revision that was actually checked out (which can be useful +when the SourceStamp in use merely requested the "latest revision": +`got_revision' will tell you what was actually built). + + In custom BuildSteps, you can get and set the build properties with +the `getProperty'/`setProperty' methods. Each takes a string for the +name of the property, and returns or accepts an arbitrary(1) object. +For example: + + class MakeTarball(ShellCommand): + def start(self): + if self.getProperty("os") == "win": + self.setCommand([ ... ]) # windows-only command + else: + self.setCommand([ ... ]) # equivalent for other systems + ShellCommand.start(self) + +WithProperties +============== + +You can use build properties in ShellCommands by using the +`WithProperties' wrapper when setting the arguments of the +ShellCommand. This interpolates the named build properties into the +generated shell command. Most step parameters accept +`WithProperties'. Please file bugs for any parameters which do not. + + from buildbot.steps.shell import ShellCommand + from buildbot.process.properties import WithProperties + + f.addStep(ShellCommand( + command=["tar", "czf", + WithProperties("build-%s.tar.gz", "revision"), + "source"])) + + If this BuildStep were used in a tree obtained from Subversion, it +would create a tarball with a name like `build-1234.tar.gz'. + + The `WithProperties' function does `printf'-style string +interpolation, using strings obtained by calling +`build.getProperty(propname)'. Note that for every `%s' (or `%d', +etc), you must have exactly one additional argument to indicate which +build property you want to insert. + + You can also use python dictionary-style string interpolation by +using the `%(propname)s' syntax. In this form, the property name goes +in the parentheses, and WithProperties takes _no_ additional +arguments: + + f.addStep(ShellCommand( + command=["tar", "czf", + WithProperties("build-%(revision)s.tar.gz"), + "source"])) + + Don't forget the extra "s" after the closing parenthesis! This is +the cause of many confusing errors. + + The dictionary-style interpolation supports a number of more +advanced syntaxes, too. + +`propname:-replacement' + If `propname' exists, substitute its value; otherwise, + substitute `replacement'. `replacement' may be empty + (`%(propname:-)s') + +`propname:+replacement' + If `propname' exists, substitute `replacement'; otherwise, + substitute an empty string. + + + Although these are similar to shell substitutions, no other +substitutions are currently supported, and `replacement' in the above +cannot contain more substitutions. + + Note: like python, you can either do positional-argument +interpolation _or_ keyword-argument interpolation, not both. Thus you +cannot use a string like `WithProperties("foo-%(revision)s-%s", +"branch")'. + +Common Build Properties +======================= + +The following build properties are set when the build is started, and +are available to all steps. + +`branch' + This comes from the build's SourceStamp, and describes which + branch is being checked out. This will be `None' (which + interpolates into `WithProperties' as an empty string) if the + build is on the default branch, which is generally the trunk. + Otherwise it will be a string like "branches/beta1.4". The exact + syntax depends upon the VC system being used. + +`revision' + This also comes from the SourceStamp, and is the revision of the + source code tree that was requested from the VC system. When a + build is requested of a specific revision (as is generally the + case when the build is triggered by Changes), this will contain + the revision specification. This is always a string, although + the syntax depends upon the VC system in use: for SVN it is an + integer, for Mercurial it is a short string, for Darcs it is a + rather large string, etc. + + If the "force build" button was pressed, the revision will be + `None', which means to use the most recent revision available. + This is a "trunk build". This will be interpolated as an empty + string. + +`got_revision' + This is set when a Source step checks out the source tree, and + provides the revision that was actually obtained from the VC + system. In general this should be the same as `revision', + except for trunk builds, where `got_revision' indicates what + revision was current when the checkout was performed. This can + be used to rebuild the same source code later. + + Note that for some VC systems (Darcs in particular), the + revision is a large string containing newlines, and is not + suitable for interpolation into a filename. + +`buildername' + This is a string that indicates which Builder the build was a + part of. The combination of buildername and buildnumber + uniquely identify a build. + +`buildnumber' + Each build gets a number, scoped to the Builder (so the first + build performed on any given Builder will have a build number of + 0). This integer property contains the build's number. + +`slavename' + This is a string which identifies which buildslave the build is + running on. + +`scheduler' + If the build was started from a scheduler, then this property + will contain the name of that scheduler. + + + ---------- Footnotes ---------- + + (1) Build properties are serialized along with the build results, +so they must be serializable. For this reason, the value of any build +property should be simple inert data: strings, numbers, lists, +tuples, and dictionaries. They should not contain class instances. + + +File: buildbot.info, Node: Source Checkout, Next: ShellCommand, Prev: Using Build Properties, Up: Build Steps + +6.1.3 Source Checkout +--------------------- + +The first step of any build is typically to acquire the source code +from which the build will be performed. There are several classes to +handle this, one for each of the different source control system that +Buildbot knows about. For a description of how Buildbot treats source +control in general, see *note Version Control Systems::. + + All source checkout steps accept some common parameters to control +how they get the sources and where they should be placed. The +remaining per-VC-system parameters are mostly to specify where +exactly the sources are coming from. + +`mode' + a string describing the kind of VC operation that is desired. + Defaults to `update'. + + `update' + specifies that the CVS checkout/update should be performed + directly into the workdir. Each build is performed in the + same directory, allowing for incremental builds. This + minimizes disk space, bandwidth, and CPU time. However, it + may encounter problems if the build process does not handle + dependencies properly (sometimes you must do a "clean + build" to make sure everything gets compiled), or if source + files are deleted but generated files can influence test + behavior (e.g. python's .pyc files), or when source + directories are deleted but generated files prevent CVS + from removing them. Builds ought to be correct regardless + of whether they are done "from scratch" or incrementally, + but it is useful to test both kinds: this mode exercises the + incremental-build style. + + `copy' + specifies that the CVS workspace should be maintained in a + separate directory (called the 'copydir'), using checkout + or update as necessary. For each build, a new workdir is + created with a copy of the source tree (rm -rf workdir; cp + -r copydir workdir). This doubles the disk space required, + but keeps the bandwidth low (update instead of a full + checkout). A full 'clean' build is performed each time. This + avoids any generated-file build problems, but is still + occasionally vulnerable to CVS problems such as a + repository being manually rearranged, causing CVS errors on + update which are not an issue with a full checkout. + + `clobber' + specifes that the working directory should be deleted each + time, necessitating a full checkout for each build. This + insures a clean build off a complete checkout, avoiding any + of the problems described above. This mode exercises the + "from-scratch" build style. + + `export' + this is like `clobber', except that the 'cvs export' + command is used to create the working directory. This + command removes all CVS metadata files (the CVS/ + directories) from the tree, which is sometimes useful for + creating source tarballs (to avoid including the metadata + in the tar file). + +`workdir' + like all Steps, this indicates the directory where the build + will take place. Source Steps are special in that they perform + some operations outside of the workdir (like creating the + workdir itself). + +`alwaysUseLatest' + if True, bypass the usual "update to the last Change" behavior, + and always update to the latest changes instead. + +`retry' + If set, this specifies a tuple of `(delay, repeats)' which means + that when a full VC checkout fails, it should be retried up to + REPEATS times, waiting DELAY seconds between attempts. If you + don't provide this, it defaults to `None', which means VC + operations should not be retried. This is provided to make life + easier for buildslaves which are stuck behind poor network + connections. + + + My habit as a developer is to do a `cvs update' and `make' each +morning. Problems can occur, either because of bad code being checked +in, or by incomplete dependencies causing a partial rebuild to fail +where a complete from-scratch build might succeed. A quick Builder +which emulates this incremental-build behavior would use the +`mode='update'' setting. + + On the other hand, other kinds of dependency problems can cause a +clean build to fail where a partial build might succeed. This +frequently results from a link step that depends upon an object file +that was removed from a later version of the tree: in the partial +tree, the object file is still around (even though the Makefiles no +longer know how to create it). + + "official" builds (traceable builds performed from a known set of +source revisions) are always done as clean builds, to make sure it is +not influenced by any uncontrolled factors (like leftover files from a +previous build). A "full" Builder which behaves this way would want +to use the `mode='clobber'' setting. + + Each VC system has a corresponding source checkout class: their +arguments are described on the following pages. + +* Menu: + +* CVS:: +* SVN:: +* Darcs:: +* Mercurial:: +* Arch:: +* Bazaar:: +* Bzr:: +* P4:: +* Git:: + + +File: buildbot.info, Node: CVS, Next: SVN, Prev: Source Checkout, Up: Source Checkout + +6.1.3.1 CVS +........... + +The `CVS' build step performs a CVS (http://www.nongnu.org/cvs/) +checkout or update. It takes the following arguments: + +`cvsroot' + (required): specify the CVSROOT value, which points to a CVS + repository, probably on a remote machine. For example, the + cvsroot value you would use to get a copy of the Buildbot source + code is + `:pserver:anonymous@cvs.sourceforge.net:/cvsroot/buildbot' + +`cvsmodule' + (required): specify the cvs `module', which is generally a + subdirectory of the CVSROOT. The cvsmodule for the Buildbot + source code is `buildbot'. + +`branch' + a string which will be used in a `-r' argument. This is most + useful for specifying a branch to work on. Defaults to `HEAD'. + +`global_options' + a list of flags to be put before the verb in the CVS command. + +`checkoutDelay' + if set, the number of seconds to put between the timestamp of + the last known Change and the value used for the `-D' option. + Defaults to half of the parent Build's treeStableTimer. + + + +File: buildbot.info, Node: SVN, Next: Darcs, Prev: CVS, Up: Source Checkout + +6.1.3.2 SVN +........... + +The `SVN' build step performs a Subversion +(http://subversion.tigris.org) checkout or update. There are two +basic ways of setting up the checkout step, depending upon whether +you are using multiple branches or not. + + If all of your builds use the same branch, then you should create +the `SVN' step with the `svnurl' argument: + +`svnurl' + (required): this specifies the `URL' argument that will be given + to the `svn checkout' command. It dictates both where the + repository is located and which sub-tree should be extracted. In + this respect, it is like a combination of the CVS `cvsroot' and + `cvsmodule' arguments. For example, if you are using a remote + Subversion repository which is accessible through HTTP at a URL + of `http://svn.example.com/repos', and you wanted to check out + the `trunk/calc' sub-tree, you would use + `svnurl="http://svn.example.com/repos/trunk/calc"' as an argument + to your `SVN' step. + + If, on the other hand, you are building from multiple branches, +then you should create the `SVN' step with the `baseURL' and +`defaultBranch' arguments instead: + +`baseURL' + (required): this specifies the base repository URL, to which a + branch name will be appended. It should probably end in a slash. + +`defaultBranch' + this specifies the name of the branch to use when a Build does + not provide one of its own. This will be appended to `baseURL' to + create the string that will be passed to the `svn checkout' + command. + +`username' + if specified, this will be passed to the `svn' binary with a + `--username' option. + +`password' + if specified, this will be passed to the `svn' binary with a + `--password' option. The password itself will be suitably + obfuscated in the logs. + + + If you are using branches, you must also make sure your +`ChangeSource' will report the correct branch names. + +branch example +============== + +Let's suppose that the "MyProject" repository uses branches for the +trunk, for various users' individual development efforts, and for +several new features that will require some amount of work (involving +multiple developers) before they are ready to merge onto the trunk. +Such a repository might be organized as follows: + + svn://svn.example.org/MyProject/trunk + svn://svn.example.org/MyProject/branches/User1/foo + svn://svn.example.org/MyProject/branches/User1/bar + svn://svn.example.org/MyProject/branches/User2/baz + svn://svn.example.org/MyProject/features/newthing + svn://svn.example.org/MyProject/features/otherthing + + Further assume that we want the Buildbot to run tests against the +trunk and against all the feature branches (i.e., do a +checkout/compile/build of branch X when a file has been changed on +branch X, when X is in the set [trunk, features/newthing, +features/otherthing]). We do not want the Buildbot to automatically +build any of the user branches, but it should be willing to build a +user branch when explicitly requested (most likely by the user who +owns that branch). + + There are three things that need to be set up to accomodate this +system. The first is a ChangeSource that is capable of identifying the +branch which owns any given file. This depends upon a user-supplied +function, in an external program that runs in the SVN commit hook and +connects to the buildmaster's `PBChangeSource' over a TCP connection. +(you can use the "`buildbot sendchange'" utility for this purpose, +but you will still need an external program to decide what value +should be passed to the `--branch=' argument). For example, a change +to a file with the SVN url of +"svn://svn.example.org/MyProject/features/newthing/src/foo.c" should +be broken down into a Change instance with +`branch='features/newthing'' and `file='src/foo.c''. + + The second piece is an `AnyBranchScheduler' which will pay +attention to the desired branches. It will not pay attention to the +user branches, so it will not automatically start builds in response +to changes there. The AnyBranchScheduler class requires you to +explicitly list all the branches you want it to use, but it would not +be difficult to write a subclass which used +`branch.startswith('features/'' to remove the need for this explicit +list. Or, if you want to build user branches too, you can use +AnyBranchScheduler with `branches=None' to indicate that you want it +to pay attention to all branches. + + The third piece is an `SVN' checkout step that is configured to +handle the branches correctly, with a `baseURL' value that matches +the way the ChangeSource splits each file's URL into base, branch, +and file. + + from buildbot.changes.pb import PBChangeSource + from buildbot.scheduler import AnyBranchScheduler + from buildbot.process import source, factory + from buildbot.steps import source, shell + + c['change_source'] = PBChangeSource() + s1 = AnyBranchScheduler('main', + ['trunk', 'features/newthing', 'features/otherthing'], + 10*60, ['test-i386', 'test-ppc']) + c['schedulers'] = [s1] + + f = factory.BuildFactory() + f.addStep(source.SVN(mode='update', + baseURL='svn://svn.example.org/MyProject/', + defaultBranch='trunk')) + f.addStep(shell.Compile(command="make all")) + f.addStep(shell.Test(command="make test")) + + c['builders'] = [ + {'name':'test-i386', 'slavename':'bot-i386', 'builddir':'test-i386', + 'factory':f }, + {'name':'test-ppc', 'slavename':'bot-ppc', 'builddir':'test-ppc', + 'factory':f }, + ] + + In this example, when a change arrives with a `branch' attribute +of "trunk", the resulting build will have an SVN step that +concatenates "svn://svn.example.org/MyProject/" (the baseURL) with +"trunk" (the branch name) to get the correct svn command. If the +"newthing" branch has a change to "src/foo.c", then the SVN step will +concatenate "svn://svn.example.org/MyProject/" with +"features/newthing" to get the svnurl for checkout. + + +File: buildbot.info, Node: Darcs, Next: Mercurial, Prev: SVN, Up: Source Checkout + +6.1.3.3 Darcs +............. + +The `Darcs' build step performs a Darcs (http://darcs.net/) checkout +or update. + + Like *Note SVN::, this step can either be configured to always +check out a specific tree, or set up to pull from a particular branch +that gets specified separately for each build. Also like SVN, the +repository URL given to Darcs is created by concatenating a `baseURL' +with the branch name, and if no particular branch is requested, it +uses a `defaultBranch'. The only difference in usage is that each +potential Darcs repository URL must point to a fully-fledged +repository, whereas SVN URLs usually point to sub-trees of the main +Subversion repository. In other words, doing an SVN checkout of +`baseURL' is legal, but silly, since you'd probably wind up with a +copy of every single branch in the whole repository. Doing a Darcs +checkout of `baseURL' is just plain wrong, since the parent directory +of a collection of Darcs repositories is not itself a valid +repository. + + The Darcs step takes the following arguments: + +`repourl' + (required unless `baseURL' is provided): the URL at which the + Darcs source repository is available. + +`baseURL' + (required unless `repourl' is provided): the base repository URL, + to which a branch name will be appended. It should probably end + in a slash. + +`defaultBranch' + (allowed if and only if `baseURL' is provided): this specifies + the name of the branch to use when a Build does not provide one + of its own. This will be appended to `baseURL' to create the + string that will be passed to the `darcs get' command. + + +File: buildbot.info, Node: Mercurial, Next: Arch, Prev: Darcs, Up: Source Checkout + +6.1.3.4 Mercurial +................. + +The `Mercurial' build step performs a Mercurial +(http://selenic.com/mercurial) (aka "hg") checkout or update. + + Branches are handled just like *Note Darcs::. + + The Mercurial step takes the following arguments: + +`repourl' + (required unless `baseURL' is provided): the URL at which the + Mercurial source repository is available. + +`baseURL' + (required unless `repourl' is provided): the base repository URL, + to which a branch name will be appended. It should probably end + in a slash. + +`defaultBranch' + (allowed if and only if `baseURL' is provided): this specifies + the name of the branch to use when a Build does not provide one + of its own. This will be appended to `baseURL' to create the + string that will be passed to the `hg clone' command. + + +File: buildbot.info, Node: Arch, Next: Bazaar, Prev: Mercurial, Up: Source Checkout + +6.1.3.5 Arch +............ + +The `Arch' build step performs an Arch (http://gnuarch.org/) checkout +or update using the `tla' client. It takes the following arguments: + +`url' + (required): this specifies the URL at which the Arch source + archive is available. + +`version' + (required): this specifies which "development line" (like a + branch) should be used. This provides the default branch name, + but individual builds may specify a different one. + +`archive' + (optional): Each repository knows its own archive name. If this + parameter is provided, it must match the repository's archive + name. The parameter is accepted for compatibility with the + `Bazaar' step, below. + + + +File: buildbot.info, Node: Bazaar, Next: Bzr, Prev: Arch, Up: Source Checkout + +6.1.3.6 Bazaar +.............. + +`Bazaar' is an alternate implementation of the Arch VC system, which +uses a client named `baz'. The checkout semantics are just different +enough from `tla' that there is a separate BuildStep for it. + + It takes exactly the same arguments as `Arch', except that the +`archive=' parameter is required. (baz does not emit the archive name +when you do `baz register-archive', so we must provide it ourselves). + + +File: buildbot.info, Node: Bzr, Next: P4, Prev: Bazaar, Up: Source Checkout + +6.1.3.7 Bzr +........... + +`bzr' is a descendant of Arch/Baz, and is frequently referred to as +simply "Bazaar". The repository-vs-workspace model is similar to +Darcs, but it uses a strictly linear sequence of revisions (one +history per branch) like Arch. Branches are put in subdirectories. +This makes it look very much like Mercurial, so it takes the same +arguments: + +`repourl' + (required unless `baseURL' is provided): the URL at which the + Bzr source repository is available. + +`baseURL' + (required unless `repourl' is provided): the base repository URL, + to which a branch name will be appended. It should probably end + in a slash. + +`defaultBranch' + (allowed if and only if `baseURL' is provided): this specifies + the name of the branch to use when a Build does not provide one + of its own. This will be appended to `baseURL' to create the + string that will be passed to the `bzr checkout' command. + + +File: buildbot.info, Node: P4, Next: Git, Prev: Bzr, Up: Source Checkout + +6.1.3.8 P4 +.......... + +The `P4' build step creates a Perforce (http://www.perforce.com/) +client specification and performs an update. + +`p4base' + A view into the Perforce depot without branch name or trailing + "...". Typically "//depot/proj/". + +`defaultBranch' + A branch name to append on build requests if none is specified. + Typically "trunk". + +`p4port' + (optional): the host:port string describing how to get to the P4 + Depot (repository), used as the -p argument for all p4 commands. + +`p4user' + (optional): the Perforce user, used as the -u argument to all p4 + commands. + +`p4passwd' + (optional): the Perforce password, used as the -p argument to + all p4 commands. + +`p4extra_views' + (optional): a list of (depotpath, clientpath) tuples containing + extra views to be mapped into the client specification. Both + will have "/..." appended automatically. The client name and + source directory will be prepended to the client path. + +`p4client' + (optional): The name of the client to use. In mode='copy' and + mode='update', it's particularly important that a unique name is + used for each checkout directory to avoid incorrect + synchronization. For this reason, Python percent substitution + will be performed on this value to replace %(slave)s with the + slave name and %(builder)s with the builder name. The default is + "buildbot_%(slave)s_%(build)s". + + +File: buildbot.info, Node: Git, Prev: P4, Up: Source Checkout + +6.1.3.9 Git +........... + +The `Git' build step clones or updates a Git (http://git.or.cz/) +repository and checks out the specified branch or revision. Note that +the buildbot supports Git version 1.2.0 and later: earlier versions +(such as the one shipped in Ubuntu 'Dapper') do not support the `git +init' command that the buildbot uses. + + The Git step takes the following arguments: + +`repourl' + (required): the URL of the upstream Git repository. + +`branch' + (optional): this specifies the name of the branch to use when a + Build does not provide one of its own. If this this parameter is + not specified, and the Build does not provide a branch, the + "master" branch will be used. + + +File: buildbot.info, Node: ShellCommand, Next: Simple ShellCommand Subclasses, Prev: Source Checkout, Up: Build Steps + +6.1.4 ShellCommand +------------------ + +This is a useful base class for just about everything you might want +to do during a build (except for the initial source checkout). It runs +a single command in a child shell on the buildslave. All stdout/stderr +is recorded into a LogFile. The step finishes with a status of FAILURE +if the command's exit code is non-zero, otherwise it has a status of +SUCCESS. + + The preferred way to specify the command is with a list of argv +strings, since this allows for spaces in filenames and avoids doing +any fragile shell-escaping. You can also specify the command with a +single string, in which case the string is given to '/bin/sh -c +COMMAND' for parsing. + + On Windows, commands are run via `cmd.exe /c' which works well. +However, if you're running a batch file, the error level does not get +propagated correctly unless you add 'call' before your batch file's +name: `cmd=['call', 'myfile.bat', ...]'. + + All ShellCommands are run by default in the "workdir", which +defaults to the "`build'" subdirectory of the slave builder's base +directory. The absolute path of the workdir will thus be the slave's +basedir (set as an option to `buildbot create-slave', *note Creating +a buildslave::) plus the builder's basedir (set in the builder's +`c['builddir']' key in master.cfg) plus the workdir itself (a +class-level attribute of the BuildFactory, defaults to "`build'"). + + `ShellCommand' arguments: + +`command' + a list of strings (preferred) or single string (discouraged) + which specifies the command to be run. A list of strings is + preferred because it can be used directly as an argv array. + Using a single string (with embedded spaces) requires the + buildslave to pass the string to /bin/sh for interpretation, + which raises all sorts of difficult questions about how to + escape or interpret shell metacharacters. + +`env' + a dictionary of environment strings which will be added to the + child command's environment. For example, to run tests with a + different i18n language setting, you might use + + f.addStep(ShellCommand(command=["make", "test"], + env={'LANG': 'fr_FR'})) + + These variable settings will override any existing ones in the + buildslave's environment or the environment specified in the + Builder. The exception is PYTHONPATH, which is merged with + (actually prepended to) any existing $PYTHONPATH setting. The + value is treated as a list of directories to prepend, and a + single string is treated like a one-item list. For example, to + prepend both `/usr/local/lib/python2.3' and + `/home/buildbot/lib/python' to any existing $PYTHONPATH setting, + you would do something like the following: + + f.addStep(ShellCommand( + command=["make", "test"], + env={'PYTHONPATH': ["/usr/local/lib/python2.3", + "/home/buildbot/lib/python"] })) + +`want_stdout' + if False, stdout from the child process is discarded rather than + being sent to the buildmaster for inclusion in the step's + LogFile. + +`want_stderr' + like `want_stdout' but for stderr. Note that commands run through + a PTY do not have separate stdout/stderr streams: both are + merged into stdout. + +`usePTY' + Should this command be run in a `pty'? The default is to + observe the configuration of the client (*note Buildslave + Options::), but specifying `True' or `False' here will override + the default. + + The advantage of using a PTY is that "grandchild" processes are + more likely to be cleaned up if the build is interrupted or + times out (since it enables the use of a "process group" in + which all child processes will be placed). The disadvantages: + some forms of Unix have problems with PTYs, some of your unit + tests may behave differently when run under a PTY (generally + those which check to see if they are being run interactively), + and PTYs will merge the stdout and stderr streams into a single + output stream (which means the red-vs-black coloring in the + logfiles will be lost). + +`logfiles' + Sometimes commands will log interesting data to a local file, + rather than emitting everything to stdout or stderr. For + example, Twisted's "trial" command (which runs unit tests) only + presents summary information to stdout, and puts the rest into a + file named `_trial_temp/test.log'. It is often useful to watch + these files as the command runs, rather than using `/bin/cat' to + dump their contents afterwards. + + The `logfiles=' argument allows you to collect data from these + secondary logfiles in near-real-time, as the step is running. It + accepts a dictionary which maps from a local Log name (which is + how the log data is presented in the build results) to a remote + filename (interpreted relative to the build's working + directory). Each named file will be polled on a regular basis + (every couple of seconds) as the build runs, and any new text + will be sent over to the buildmaster. + + f.addStep(ShellCommand( + command=["make", "test"], + logfiles={"triallog": "_trial_temp/test.log"})) + +`timeout' + if the command fails to produce any output for this many + seconds, it is assumed to be locked up and will be killed. + +`description' + This will be used to describe the command (on the Waterfall + display) while the command is still running. It should be a + single imperfect-tense verb, like "compiling" or "testing". The + preferred form is a list of short strings, which allows the HTML + Waterfall display to create narrower columns by emitting a <br> + tag between each word. You may also provide a single string. + +`descriptionDone' + This will be used to describe the command once it has finished. A + simple noun like "compile" or "tests" should be used. Like + `description', this may either be a list of short strings or a + single string. + + If neither `description' nor `descriptionDone' are set, the + actual command arguments will be used to construct the + description. This may be a bit too wide to fit comfortably on + the Waterfall display. + + f.addStep(ShellCommand(command=["make", "test"], + description=["testing"], + descriptionDone=["tests"])) + +`logEnviron' + If this option is true (the default), then the step's logfile + will describe the environment variables on the slave. In + situations where the environment is not relevant and is long, it + may be easier to set `logEnviron=False'. + + + +File: buildbot.info, Node: Simple ShellCommand Subclasses, Next: Python BuildSteps, Prev: ShellCommand, Up: Build Steps + +6.1.5 Simple ShellCommand Subclasses +------------------------------------ + +Several subclasses of ShellCommand are provided as starting points for +common build steps. These are all very simple: they just override a +few parameters so you don't have to specify them yourself, making the +master.cfg file less verbose. + +* Menu: + +* Configure:: +* Compile:: +* Test:: +* TreeSize:: +* PerlModuleTest:: +* SetProperty:: + + +File: buildbot.info, Node: Configure, Next: Compile, Prev: Simple ShellCommand Subclasses, Up: Simple ShellCommand Subclasses + +6.1.5.1 Configure +................. + +This is intended to handle the `./configure' step from autoconf-style +projects, or the `perl Makefile.PL' step from perl MakeMaker.pm-style +modules. The default command is `./configure' but you can change this +by providing a `command=' parameter. + + +File: buildbot.info, Node: Compile, Next: Test, Prev: Configure, Up: Simple ShellCommand Subclasses + +6.1.5.2 Compile +............... + +This is meant to handle compiling or building a project written in C. +The default command is `make all'. When the compile is finished, the +log file is scanned for GCC warning messages, a summary log is +created with any problems that were seen, and the step is marked as +WARNINGS if any were discovered. The number of warnings is stored in a +Build Property named "warnings-count", which is accumulated over all +Compile steps (so if two warnings are found in one step, and three are +found in another step, the overall build will have a "warnings-count" +property of 5. + + The default regular expression used to detect a warning is +`'.*warning[: ].*'' , which is fairly liberal and may cause +false-positives. To use a different regexp, provide a +`warningPattern=' argument, or use a subclass which sets the +`warningPattern' attribute: + + f.addStep(Compile(command=["make", "test"], + warningPattern="^Warning: ")) + + The `warningPattern=' can also be a pre-compiled python regexp +object: this makes it possible to add flags like `re.I' (to use +case-insensitive matching). + + (TODO: this step needs to be extended to look for GCC error +messages as well, and collect them into a separate logfile, along +with the source code filenames involved). + + +File: buildbot.info, Node: Test, Next: TreeSize, Prev: Compile, Up: Simple ShellCommand Subclasses + +6.1.5.3 Test +............ + +This is meant to handle unit tests. The default command is `make +test', and the `warnOnFailure' flag is set. + + +File: buildbot.info, Node: TreeSize, Next: PerlModuleTest, Prev: Test, Up: Simple ShellCommand Subclasses + +6.1.5.4 TreeSize +................ + +This is a simple command that uses the 'du' tool to measure the size +of the code tree. It puts the size (as a count of 1024-byte blocks, +aka 'KiB' or 'kibibytes') on the step's status text, and sets a build +property named 'tree-size-KiB' with the same value. + + +File: buildbot.info, Node: PerlModuleTest, Next: SetProperty, Prev: TreeSize, Up: Simple ShellCommand Subclasses + +6.1.5.5 PerlModuleTest +...................... + +This is a simple command that knows how to run tests of perl modules. +It parses the output to determine the number of tests passed and +failed and total number executed, saving the results for later query. + + +File: buildbot.info, Node: SetProperty, Prev: PerlModuleTest, Up: Simple ShellCommand Subclasses + +6.1.5.6 SetProperty +................... + +This buildstep is similar to ShellCommand, except that it captures the +output of the command into a property. It is usually used like this: + + f.addStep(SetProperty(command="uname -a", property="uname")) + + This runs `uname -a' and captures its stdout, stripped of leading +and trailing whitespace, in the property "uname". To avoid stripping, +add `strip=False'. The `property' argument can be specified as a +`WithProperties' object. + + The more advanced usage allows you to specify a function to extract +properties from the command output. Here you can use regular +expressions, string interpolation, or whatever you would like. The +function is called with three arguments: the exit status of the +command, its standard output as a string, and its standard error as a +string. It should return a dictionary containing all new properties. + + def glob2list(rc, stdout, stderr): + jpgs = [ l.strip() for l in stdout.split('\n') ] + return { 'jpgs' : jpgs } + f.addStep(SetProperty(command="ls -1 *.jpg", extract_fn=glob2list)) + + Note that any ordering relationship of the contents of stdout and +stderr is lost. For example, given + + f.addStep(SetProperty( + command="echo output1; echo error >&2; echo output2", + extract_fn=my_extract)) + + Then `my_extract' will see `stdout="output1\noutput2\n"' and +`stderr="error\n"'. + + +File: buildbot.info, Node: Python BuildSteps, Next: Transferring Files, Prev: Simple ShellCommand Subclasses, Up: Build Steps + +6.1.6 Python BuildSteps +----------------------- + +Here are some BuildSteps that are specifcally useful for projects +implemented in Python. + +* Menu: + +* BuildEPYDoc:: +* PyFlakes:: +* PyLint:: + + +File: buildbot.info, Node: BuildEPYDoc, Next: PyFlakes, Up: Python BuildSteps + +6.1.6.1 BuildEPYDoc +................... + +epydoc (http://epydoc.sourceforge.net/) is a tool for generating API +documentation for Python modules from their docstrings. It reads all +the .py files from your source tree, processes the docstrings +therein, and creates a large tree of .html files (or a single .pdf +file). + + The `buildbot.steps.python.BuildEPYDoc' step will run `epydoc' to +produce this API documentation, and will count the errors and +warnings from its output. + + You must supply the command line to be used. The default is `make +epydocs', which assumes that your project has a Makefile with an +"epydocs" target. You might wish to use something like `epydoc -o +apiref source/PKGNAME' instead. You might also want to add `--pdf' to +generate a PDF file instead of a large tree of HTML files. + + The API docs are generated in-place in the build tree (under the +workdir, in the subdirectory controlled by the "-o" argument). To +make them useful, you will probably have to copy them to somewhere +they can be read. A command like `rsync -ad apiref/ +dev.example.com:~public_html/current-apiref/' might be useful. You +might instead want to bundle them into a tarball and publish it in the +same place where the generated install tarball is placed. + + from buildbot.steps.python import BuildEPYDoc + + ... + f.addStep(BuildEPYDoc(command=["epydoc", "-o", "apiref", "source/mypkg"])) + + +File: buildbot.info, Node: PyFlakes, Next: PyLint, Prev: BuildEPYDoc, Up: Python BuildSteps + +6.1.6.2 PyFlakes +................ + +PyFlakes (http://divmod.org/trac/wiki/DivmodPyflakes) is a tool to +perform basic static analysis of Python code to look for simple +errors, like missing imports and references of undefined names. It is +like a fast and simple form of the C "lint" program. Other tools +(like pychecker) provide more detailed results but take longer to run. + + The `buildbot.steps.python.PyFlakes' step will run pyflakes and +count the various kinds of errors and warnings it detects. + + You must supply the command line to be used. The default is `make +pyflakes', which assumes you have a top-level Makefile with a +"pyflakes" target. You might want to use something like `pyflakes .' +or `pyflakes src'. + + from buildbot.steps.python import PyFlakes + + ... + f.addStep(PyFlakes(command=["pyflakes", "src"])) + + +File: buildbot.info, Node: PyLint, Prev: PyFlakes, Up: Python BuildSteps + +6.1.6.3 PyLint +.............. + +Similarly, the `buildbot.steps.python.PyLint' step will run pylint and +analyze the results. + + You must supply the command line to be used. There is no default. + + from buildbot.steps.python import PyLint + + ... + f.addStep(PyLint(command=["pylint", "src"])) + + +File: buildbot.info, Node: Transferring Files, Next: Steps That Run on the Master, Prev: Python BuildSteps, Up: Build Steps + +6.1.7 Transferring Files +------------------------ + +Most of the work involved in a build will take place on the +buildslave. But occasionally it is useful to do some work on the +buildmaster side. The most basic way to involve the buildmaster is +simply to move a file from the slave to the master, or vice versa. +There are a pair of BuildSteps named `FileUpload' and `FileDownload' +to provide this functionality. `FileUpload' moves a file _up to_ the +master, while `FileDownload' moves a file _down from_ the master. + + As an example, let's assume that there is a step which produces an +HTML file within the source tree that contains some sort of generated +project documentation. We want to move this file to the buildmaster, +into a `~/public_html' directory, so it can be visible to developers. +This file will wind up in the slave-side working directory under the +name `docs/reference.html'. We want to put it into the master-side +`~/public_html/ref.html'. + + from buildbot.steps.shell import ShellCommand + from buildbot.steps.transfer import FileUpload + + f.addStep(ShellCommand(command=["make", "docs"])) + f.addStep(FileUpload(slavesrc="docs/reference.html", + masterdest="~/public_html/ref.html")) + + The `masterdest=' argument will be passed to os.path.expanduser, +so things like "~" will be expanded properly. Non-absolute paths will +be interpreted relative to the buildmaster's base directory. +Likewise, the `slavesrc=' argument will be expanded and interpreted +relative to the builder's working directory. + + To move a file from the master to the slave, use the +`FileDownload' command. For example, let's assume that some step +requires a configuration file that, for whatever reason, could not be +recorded in the source code repository or generated on the buildslave +side: + + from buildbot.steps.shell import ShellCommand + from buildbot.steps.transfer import FileUpload + + f.addStep(FileDownload(mastersrc="~/todays_build_config.txt", + slavedest="build_config.txt")) + f.addStep(ShellCommand(command=["make", "config"])) + + Like `FileUpload', the `mastersrc=' argument is interpreted +relative to the buildmaster's base directory, and the `slavedest=' +argument is relative to the builder's working directory. If the +buildslave is running in `~buildslave', and the builder's "builddir" +is something like `tests-i386', then the workdir is going to be +`~buildslave/tests-i386/build', and a `slavedest=' of `foo/bar.html' +will get put in `~buildslave/tests-i386/build/foo/bar.html'. Both of +these commands will create any missing intervening directories. + +Other Parameters +---------------- + +The `maxsize=' argument lets you set a maximum size for the file to +be transferred. This may help to avoid surprises: transferring a +100MB coredump when you were expecting to move a 10kB status file +might take an awfully long time. The `blocksize=' argument controls +how the file is sent over the network: larger blocksizes are slightly +more efficient but also consume more memory on each end, and there is +a hard-coded limit of about 640kB. + + The `mode=' argument allows you to control the access permissions +of the target file, traditionally expressed as an octal integer. The +most common value is probably 0755, which sets the "x" executable bit +on the file (useful for shell scripts and the like). The default +value for `mode=' is None, which means the permission bits will +default to whatever the umask of the writing process is. The default +umask tends to be fairly restrictive, but at least on the buildslave +you can make it less restrictive with a -umask command-line option at +creation time (*note Buildslave Options::). + +Transfering Directories +----------------------- + +To transfer complete directories from the buildslave to the master, +there is a BuildStep named `DirectoryUpload'. It works like +`FileUpload', just for directories. However it does not support the +`maxsize', `blocksize' and `mode' arguments. As an example, let's +assume an generated project documentation, which consists of many +files (like the output of doxygen or epydoc). We want to move the +entire documentation to the buildmaster, into a `~/public_html/docs' +directory. On the slave-side the directory can be found under `docs': + + from buildbot.steps.shell import ShellCommand + from buildbot.steps.transfer import DirectoryUpload + + f.addStep(ShellCommand(command=["make", "docs"])) + f.addStep(DirectoryUpload(slavesrc="docs", + masterdest="~/public_html/docs")) + + The DirectoryUpload step will create all necessary directories and +transfers empty directories, too. + + +File: buildbot.info, Node: Steps That Run on the Master, Next: Triggering Schedulers, Prev: Transferring Files, Up: Build Steps + +6.1.8 Steps That Run on the Master +---------------------------------- + +Occasionally, it is useful to execute some task on the master, for +example to create a directory, deploy a build result, or trigger some +other centralized processing. This is possible, in a limited +fashion, with the `MasterShellCommand' step. + + This step operates similarly to a regular `ShellCommand', but +executes on the master, instead of the slave. To be clear, the +enclosing `Build' object must still have a slave object, just as for +any other step - only, in this step, the slave does not do anything. + + In this example, the step renames a tarball based on the day of +the week. + + from buildbot.steps.transfer import FileUpload + from buildbot.steps.master import MasterShellCommand + + f.addStep(FileUpload(slavesrc="widgetsoft.tar.gz", + masterdest="/var/buildoutputs/widgetsoft-new.tar.gz")) + f.addStep(MasterShellCommand(command=""" + cd /var/buildoutputs; + mv widgetsoft-new.tar.gz widgetsoft-`date +%a`.tar.gz""")) + + +File: buildbot.info, Node: Triggering Schedulers, Next: Writing New BuildSteps, Prev: Steps That Run on the Master, Up: Build Steps + +6.1.9 Triggering Schedulers +--------------------------- + +The counterpart to the Triggerable described in section *note +Triggerable Scheduler:: is the Trigger BuildStep. + + from buildbot.steps.trigger import Trigger + f.addStep(Trigger(schedulerNames=['build-prep'], + waitForFinish=True, + updateSourceStamp=True)) + + The `schedulerNames=' argument lists the Triggerables that should +be triggered when this step is executed. Note that it is possible, +but not advisable, to create a cycle where a build continually +triggers itself, because the schedulers are specified by name. + + If `waitForFinish' is True, then the step will not finish until +all of the builds from the triggered schedulers have finished. If this +argument is False (the default) or not given, then the buildstep +succeeds immediately after triggering the schedulers. + + If `updateSourceStamp' is True (the default), then step updates +the SourceStamp given to the Triggerables to include `got_revision' +(the revision actually used in this build) as `revision' (the +revision to use in the triggered builds). This is useful to ensure +that all of the builds use exactly the same SourceStamp, even if +other Changes have occurred while the build was running. + + +File: buildbot.info, Node: Writing New BuildSteps, Prev: Triggering Schedulers, Up: Build Steps + +6.1.10 Writing New BuildSteps +----------------------------- + +While it is a good idea to keep your build process self-contained in +the source code tree, sometimes it is convenient to put more +intelligence into your Buildbot configuration. One way to do this is +to write a custom BuildStep. Once written, this Step can be used in +the `master.cfg' file. + + The best reason for writing a custom BuildStep is to better parse +the results of the command being run. For example, a BuildStep that +knows about JUnit could look at the logfiles to determine which tests +had been run, how many passed and how many failed, and then report +more detailed information than a simple `rc==0' -based "good/bad" +decision. + +* Menu: + +* Writing BuildStep Constructors:: +* BuildStep LogFiles:: +* Reading Logfiles:: +* Adding LogObservers:: +* BuildStep URLs:: + + +File: buildbot.info, Node: Writing BuildStep Constructors, Next: BuildStep LogFiles, Up: Writing New BuildSteps + +6.1.10.1 Writing BuildStep Constructors +....................................... + +BuildStep classes have some extra equipment, because they are their +own factories. Consider the use of a BuildStep in `master.cfg': + + f.addStep(MyStep(someopt="stuff", anotheropt=1)) + + This creates a single instance of class `MyStep'. However, +Buildbot needs a new object each time the step is executed. this is +accomplished by storing the information required to instantiate a new +object in the `factory' attribute. When the time comes to construct +a new Build, BuildFactory consults this attribute (via +`getStepFactory') and instantiates a new step object. + + When writing a new step class, then, keep in mind are that you +cannot do anything "interesting" in the constructor - limit yourself +to checking and storing arguments. To ensure that these arguments +are provided to any new objects, call `self.addFactoryArguments' with +any keyword arguments your constructor needs. + + Keep a `**kwargs' argument on the end of your options, and pass +that up to the parent class's constructor. + + The whole thing looks like this: + + class Frobinfy(LoggingBuildStep): + def __init__(self, + frob_what="frobee", + frob_how_many=None, + frob_how=None, + **kwargs) + + # check + if frob_how_many is None: + raise TypeError("Frobinfy argument how_many is required") + + # call parent + LoggingBuildStep.__init__(self, **kwargs) + + # and record arguments for later + self.addFactoryArguments( + frob_what=frob_what, + frob_how_many=frob_how_many, + frob_how=frob_how) + + class FastFrobnify(Frobnify): + def __init__(self, + speed=5, + **kwargs) + Frobnify.__init__(self, **kwargs) + self.addFactoryArguments( + speed=speed) + + +File: buildbot.info, Node: BuildStep LogFiles, Next: Reading Logfiles, Prev: Writing BuildStep Constructors, Up: Writing New BuildSteps + +6.1.10.2 BuildStep LogFiles +........................... + +Each BuildStep has a collection of "logfiles". Each one has a short +name, like "stdio" or "warnings". Each LogFile contains an arbitrary +amount of text, usually the contents of some output file generated +during a build or test step, or a record of everything that was +printed to stdout/stderr during the execution of some command. + + These LogFiles are stored to disk, so they can be retrieved later. + + Each can contain multiple "channels", generally limited to three +basic ones: stdout, stderr, and "headers". For example, when a +ShellCommand runs, it writes a few lines to the "headers" channel to +indicate the exact argv strings being run, which directory the command +is being executed in, and the contents of the current environment +variables. Then, as the command runs, it adds a lot of "stdout" and +"stderr" messages. When the command finishes, a final "header" line +is added with the exit code of the process. + + Status display plugins can format these different channels in +different ways. For example, the web page shows LogFiles as text/html, +with header lines in blue text, stdout in black, and stderr in red. A +different URL is available which provides a text/plain format, in +which stdout and stderr are collapsed together, and header lines are +stripped completely. This latter option makes it easy to save the +results to a file and run `grep' or whatever against the output. + + Each BuildStep contains a mapping (implemented in a python +dictionary) from LogFile name to the actual LogFile objects. Status +plugins can get a list of LogFiles to display, for example, a list of +HREF links that, when clicked, provide the full contents of the +LogFile. + +Using LogFiles in custom BuildSteps +=================================== + +The most common way for a custom BuildStep to use a LogFile is to +summarize the results of a ShellCommand (after the command has +finished running). For example, a compile step with thousands of lines +of output might want to create a summary of just the warning messages. +If you were doing this from a shell, you would use something like: + + grep "warning:" output.log >warnings.log + + In a custom BuildStep, you could instead create a "warnings" +LogFile that contained the same text. To do this, you would add code +to your `createSummary' method that pulls lines from the main output +log and creates a new LogFile with the results: + + def createSummary(self, log): + warnings = [] + for line in log.readlines(): + if "warning:" in line: + warnings.append() + self.addCompleteLog('warnings', "".join(warnings)) + + This example uses the `addCompleteLog' method, which creates a new +LogFile, puts some text in it, and then "closes" it, meaning that no +further contents will be added. This LogFile will appear in the HTML +display under an HREF with the name "warnings", since that is the +name of the LogFile. + + You can also use `addHTMLLog' to create a complete (closed) +LogFile that contains HTML instead of plain text. The normal LogFile +will be HTML-escaped if presented through a web page, but the HTML +LogFile will not. At the moment this is only used to present a pretty +HTML representation of an otherwise ugly exception traceback when +something goes badly wrong during the BuildStep. + + In contrast, you might want to create a new LogFile at the +beginning of the step, and add text to it as the command runs. You +can create the LogFile and attach it to the build by calling +`addLog', which returns the LogFile object. You then add text to this +LogFile by calling methods like `addStdout' and `addHeader'. When you +are done, you must call the `finish' method so the LogFile can be +closed. It may be useful to create and populate a LogFile like this +from a LogObserver method *Note Adding LogObservers::. + + The `logfiles=' argument to `ShellCommand' (see *note +ShellCommand::) creates new LogFiles and fills them in realtime by +asking the buildslave to watch a actual file on disk. The buildslave +will look for additions in the target file and report them back to +the BuildStep. These additions will be added to the LogFile by +calling `addStdout'. These secondary LogFiles can be used as the +source of a LogObserver just like the normal "stdio" LogFile. + + +File: buildbot.info, Node: Reading Logfiles, Next: Adding LogObservers, Prev: BuildStep LogFiles, Up: Writing New BuildSteps + +6.1.10.3 Reading Logfiles +......................... + +Once a LogFile has been added to a BuildStep with `addLog()', +`addCompleteLog()', `addHTMLLog()', or `logfiles=', your BuildStep +can retrieve it by using `getLog()': + + class MyBuildStep(ShellCommand): + logfiles = { "nodelog": "_test/node.log" } + + def evaluateCommand(self, cmd): + nodelog = self.getLog("nodelog") + if "STARTED" in nodelog.getText(): + return SUCCESS + else: + return FAILURE + + For a complete list of the methods you can call on a LogFile, +please see the docstrings on the `IStatusLog' class in +`buildbot/interfaces.py'. + + +File: buildbot.info, Node: Adding LogObservers, Next: BuildStep URLs, Prev: Reading Logfiles, Up: Writing New BuildSteps + +6.1.10.4 Adding LogObservers +............................ + +Most shell commands emit messages to stdout or stderr as they operate, +especially if you ask them nicely with a `--verbose' flag of some +sort. They may also write text to a log file while they run. Your +BuildStep can watch this output as it arrives, to keep track of how +much progress the command has made. You can get a better measure of +progress by counting the number of source files compiled or test cases +run than by merely tracking the number of bytes that have been written +to stdout. This improves the accuracy and the smoothness of the ETA +display. + + To accomplish this, you will need to attach a `LogObserver' to one +of the log channels, most commonly to the "stdio" channel but perhaps +to another one which tracks a log file. This observer is given all +text as it is emitted from the command, and has the opportunity to +parse that output incrementally. Once the observer has decided that +some event has occurred (like a source file being compiled), it can +use the `setProgress' method to tell the BuildStep about the progress +that this event represents. + + There are a number of pre-built `LogObserver' classes that you can +choose from (defined in `buildbot.process.buildstep', and of course +you can subclass them to add further customization. The +`LogLineObserver' class handles the grunt work of buffering and +scanning for end-of-line delimiters, allowing your parser to operate +on complete stdout/stderr lines. (Lines longer than a set maximum +length are dropped; the maximum defaults to 16384 bytes, but you can +change it by calling `setMaxLineLength()' on your `LogLineObserver' +instance. Use `sys.maxint' for effective infinity.) + + For example, let's take a look at the `TrialTestCaseCounter', +which is used by the Trial step to count test cases as they are run. +As Trial executes, it emits lines like the following: + + buildbot.test.test_config.ConfigTest.testDebugPassword ... [OK] + buildbot.test.test_config.ConfigTest.testEmpty ... [OK] + buildbot.test.test_config.ConfigTest.testIRC ... [FAIL] + buildbot.test.test_config.ConfigTest.testLocks ... [OK] + + When the tests are finished, trial emits a long line of "======" +and then some lines which summarize the tests that failed. We want to +avoid parsing these trailing lines, because their format is less +well-defined than the "[OK]" lines. + + The parser class looks like this: + + from buildbot.process.buildstep import LogLineObserver + + class TrialTestCaseCounter(LogLineObserver): + _line_re = re.compile(r'^([\w\.]+) \.\.\. \[([^\]]+)\]$') + numTests = 0 + finished = False + + def outLineReceived(self, line): + if self.finished: + return + if line.startswith("=" * 40): + self.finished = True + return + + m = self._line_re.search(line.strip()) + if m: + testname, result = m.groups() + self.numTests += 1 + self.step.setProgress('tests', self.numTests) + + This parser only pays attention to stdout, since that's where trial +writes the progress lines. It has a mode flag named `finished' to +ignore everything after the "====" marker, and a scary-looking +regular expression to match each line while hopefully ignoring other +messages that might get displayed as the test runs. + + Each time it identifies a test has been completed, it increments +its counter and delivers the new progress value to the step with +`self.step.setProgress'. This class is specifically measuring +progress along the "tests" metric, in units of test cases (as opposed +to other kinds of progress like the "output" metric, which measures +in units of bytes). The Progress-tracking code uses each progress +metric separately to come up with an overall completion percentage +and an ETA value. + + To connect this parser into the `Trial' BuildStep, +`Trial.__init__' ends with the following clause: + + # this counter will feed Progress along the 'test cases' metric + counter = TrialTestCaseCounter() + self.addLogObserver('stdio', counter) + self.progressMetrics += ('tests',) + + This creates a TrialTestCaseCounter and tells the step that the +counter wants to watch the "stdio" log. The observer is automatically +given a reference to the step in its `.step' attribute. + +A Somewhat Whimsical Example +---------------------------- + +Let's say that we've got some snazzy new unit-test framework called +Framboozle. It's the hottest thing since sliced bread. It slices, it +dices, it runs unit tests like there's no tomorrow. Plus if your unit +tests fail, you can use its name for a Web 2.1 startup company, make +millions of dollars, and hire engineers to fix the bugs for you, while +you spend your afternoons lazily hang-gliding along a scenic pacific +beach, blissfully unconcerned about the state of your tests.(1) + + To run a Framboozle-enabled test suite, you just run the +'framboozler' command from the top of your source code tree. The +'framboozler' command emits a bunch of stuff to stdout, but the most +interesting bit is that it emits the line "FNURRRGH!" every time it +finishes running a test case(2). You'd like to have a test-case +counting LogObserver that watches for these lines and counts them, +because counting them will help the buildbot more accurately +calculate how long the build will take, and this will let you know +exactly how long you can sneak out of the office for your +hang-gliding lessons without anyone noticing that you're gone. + + This will involve writing a new BuildStep (probably named +"Framboozle") which inherits from ShellCommand. The BuildStep class +definition itself will look something like this: + + # START + from buildbot.steps.shell import ShellCommand + from buildbot.process.buildstep import LogLineObserver + + class FNURRRGHCounter(LogLineObserver): + numTests = 0 + def outLineReceived(self, line): + if "FNURRRGH!" in line: + self.numTests += 1 + self.step.setProgress('tests', self.numTests) + + class Framboozle(ShellCommand): + command = ["framboozler"] + + def __init__(self, **kwargs): + ShellCommand.__init__(self, **kwargs) # always upcall! + counter = FNURRRGHCounter()) + self.addLogObserver('stdio', counter) + self.progressMetrics += ('tests',) + # FINISH + + So that's the code that we want to wind up using. How do we +actually deploy it? + + You have a couple of different options. + + Option 1: The simplest technique is to simply put this text +(everything from START to FINISH) in your master.cfg file, somewhere +before the BuildFactory definition where you actually use it in a +clause like: + + f = BuildFactory() + f.addStep(SVN(svnurl="stuff")) + f.addStep(Framboozle()) + + Remember that master.cfg is secretly just a python program with one +job: populating the BuildmasterConfig dictionary. And python programs +are allowed to define as many classes as they like. So you can define +classes and use them in the same file, just as long as the class is +defined before some other code tries to use it. + + This is easy, and it keeps the point of definition very close to +the point of use, and whoever replaces you after that unfortunate +hang-gliding accident will appreciate being able to easily figure out +what the heck this stupid "Framboozle" step is doing anyways. The +downside is that every time you reload the config file, the Framboozle +class will get redefined, which means that the buildmaster will think +that you've reconfigured all the Builders that use it, even though +nothing changed. Bleh. + + Option 2: Instead, we can put this code in a separate file, and +import it into the master.cfg file just like we would the normal +buildsteps like ShellCommand and SVN. + + Create a directory named ~/lib/python, put everything from START to +FINISH in ~/lib/python/framboozle.py, and run your buildmaster using: + + PYTHONPATH=~/lib/python buildbot start MASTERDIR + + or use the `Makefile.buildbot' to control the way `buildbot start' +works. Or add something like this to something like your ~/.bashrc or +~/.bash_profile or ~/.cshrc: + + export PYTHONPATH=~/lib/python + + Once we've done this, our master.cfg can look like: + + from framboozle import Framboozle + f = BuildFactory() + f.addStep(SVN(svnurl="stuff")) + f.addStep(Framboozle()) + + or: + + import framboozle + f = BuildFactory() + f.addStep(SVN(svnurl="stuff")) + f.addStep(framboozle.Framboozle()) + + (check out the python docs for details about how "import" and +"from A import B" work). + + What we've done here is to tell python that every time it handles +an "import" statement for some named module, it should look in our +~/lib/python/ for that module before it looks anywhere else. After our +directories, it will try in a bunch of standard directories too +(including the one where buildbot is installed). By setting the +PYTHONPATH environment variable, you can add directories to the front +of this search list. + + Python knows that once it "import"s a file, it doesn't need to +re-import it again. This means that reconfiguring the buildmaster +(with "buildbot reconfig", for example) won't make it think the +Framboozle class has changed every time, so the Builders that use it +will not be spuriously restarted. On the other hand, you either have +to start your buildmaster in a slightly weird way, or you have to +modify your environment to set the PYTHONPATH variable. + + Option 3: Install this code into a standard python library +directory + + Find out what your python's standard include path is by asking it: + + 80:warner@luther% python + Python 2.4.4c0 (#2, Oct 2 2006, 00:57:46) + [GCC 4.1.2 20060928 (prerelease) (Debian 4.1.1-15)] on linux2 + Type "help", "copyright", "credits" or "license" for more information. + >>> import sys + >>> import pprint + >>> pprint.pprint(sys.path) + ['', + '/usr/lib/python24.zip', + '/usr/lib/python2.4', + '/usr/lib/python2.4/plat-linux2', + '/usr/lib/python2.4/lib-tk', + '/usr/lib/python2.4/lib-dynload', + '/usr/local/lib/python2.4/site-packages', + '/usr/lib/python2.4/site-packages', + '/usr/lib/python2.4/site-packages/Numeric', + '/var/lib/python-support/python2.4', + '/usr/lib/site-python'] + + In this case, putting the code into +/usr/local/lib/python2.4/site-packages/framboozle.py would work just +fine. We can use the same master.cfg "import framboozle" statement as +in Option 2. By putting it in a standard include directory (instead of +the decidedly non-standard ~/lib/python), we don't even have to set +PYTHONPATH to anything special. The downside is that you probably have +to be root to write to one of those standard include directories. + + Option 4: Submit the code for inclusion in the Buildbot +distribution + + Make a fork of buildbot on http://github.com/djmitche/buildbot or +post a patch in a bug at http://buildbot.net. In either case, post a +note about your patch to the mailing list, so others can provide +feedback and, eventually, commit it. + + from buildbot.steps import framboozle + f = BuildFactory() + f.addStep(SVN(svnurl="stuff")) + f.addStep(framboozle.Framboozle()) + + And then you don't even have to install framboozle.py anywhere on +your system, since it will ship with Buildbot. You don't have to be +root, you don't have to set PYTHONPATH. But you do have to make a +good case for Framboozle being worth going into the main +distribution, you'll probably have to provide docs and some unit test +cases, you'll need to figure out what kind of beer the author likes, +and then you'll have to wait until the next release. But in some +environments, all this is easier than getting root on your +buildmaster box, so the tradeoffs may actually be worth it. + + Putting the code in master.cfg (1) makes it available to that +buildmaster instance. Putting it in a file in a personal library +directory (2) makes it available for any buildmasters you might be +running. Putting it in a file in a system-wide shared library +directory (3) makes it available for any buildmasters that anyone on +that system might be running. Getting it into the buildbot's upstream +repository (4) makes it available for any buildmasters that anyone in +the world might be running. It's all a matter of how widely you want +to deploy that new class. + + ---------- Footnotes ---------- + + (1) framboozle.com is still available. Remember, I get 10% :). + + (2) Framboozle gets very excited about running unit tests. + + +File: buildbot.info, Node: BuildStep URLs, Prev: Adding LogObservers, Up: Writing New BuildSteps + +6.1.10.5 BuildStep URLs +....................... + +Each BuildStep has a collection of "links". Like its collection of +LogFiles, each link has a name and a target URL. The web status page +creates HREFs for each link in the same box as it does for LogFiles, +except that the target of the link is the external URL instead of an +internal link to a page that shows the contents of the LogFile. + + These external links can be used to point at build information +hosted on other servers. For example, the test process might produce +an intricate description of which tests passed and failed, or some +sort of code coverage data in HTML form, or a PNG or GIF image with a +graph of memory usage over time. The external link can provide an +easy way for users to navigate from the buildbot's status page to +these external web sites or file servers. Note that the step itself is +responsible for insuring that there will be a document available at +the given URL (perhaps by using `scp' to copy the HTML output to a +`~/public_html/' directory on a remote web server). Calling `addURL' +does not magically populate a web server. + + To set one of these links, the BuildStep should call the `addURL' +method with the name of the link and the target URL. Multiple URLs can +be set. + + In this example, we assume that the `make test' command causes a +collection of HTML files to be created and put somewhere on the +coverage.example.org web server, in a filename that incorporates the +build number. + + class TestWithCodeCoverage(BuildStep): + command = ["make", "test", + WithProperties("buildnum=%s" % "buildnumber")] + + def createSummary(self, log): + buildnumber = self.getProperty("buildnumber") + url = "http://coverage.example.org/builds/%s.html" % buildnumber + self.addURL("coverage", url) + + You might also want to extract the URL from some special message +output by the build process itself: + + class TestWithCodeCoverage(BuildStep): + command = ["make", "test", + WithProperties("buildnum=%s" % "buildnumber")] + + def createSummary(self, log): + output = StringIO(log.getText()) + for line in output.readlines(): + if line.startswith("coverage-url:"): + url = line[len("coverage-url:"):].strip() + self.addURL("coverage", url) + return + + Note that a build process which emits both stdout and stderr might +cause this line to be split or interleaved between other lines. It +might be necessary to restrict the getText() call to only stdout with +something like this: + + output = StringIO("".join([c[1] + for c in log.getChunks() + if c[0] == LOG_CHANNEL_STDOUT])) + + Of course if the build is run under a PTY, then stdout and stderr +will be merged before the buildbot ever sees them, so such +interleaving will be unavoidable. + + +File: buildbot.info, Node: Interlocks, Next: Build Factories, Prev: Build Steps, Up: Build Process + +6.2 Interlocks +============== + +Until now, we assumed that a master can run builds at any slave +whenever needed or desired. Some times, you want to enforce +additional constraints on builds. For reasons like limited network +bandwidth, old slave machines, or a self-willed data base server, you +may want to limit the number of builds (or build steps) that can +access a resource. + + The mechanism used by Buildbot is known as the read/write lock.(1) +It allows either many readers or a single writer but not a +combination of readers and writers. The general lock has been +modified and extended for use in Buildbot. Firstly, the general lock +allows an infinite number of readers. In Buildbot, we often want to +put an upper limit on the number of readers, for example allowing two +out of five possible builds at the same time. To do this, the lock +counts the number of active readers. Secondly, the terms _read mode_ +and _write mode_ are confusing in Buildbot context. They have been +replaced by _counting mode_ (since the lock counts them) and +_exclusive mode_. As a result of these changes, locks in Buildbot +allow a number of builds (upto some fixed number) in counting mode, +or they allow one build in exclusive mode. + + Often, not all slaves are equal. To allow for this situation, +Buildbot allows to have a separate upper limit on the count for each +slave. In this way, you can have at most 3 concurrent builds at a +fast slave, 2 at a slightly older slave, and 1 at all other slaves. + + The final thing you can specify when you introduce a new lock is +its scope. Some constraints are global - they must be enforced over +all slaves. Other constraints are local to each slave. A _master +lock_ is used for the global constraints. You can ensure for example +that at most one build (of all builds running at all slaves) accesses +the data base server. With a _slave lock_ you can add a limit local +to each slave. With such a lock, you can for example enforce an upper +limit to the number of active builds at a slave, like above. + + Time for a few examples. Below a master lock is defined to protect +a data base, and a slave lock is created to limit the number of +builds at each slave. + + from buildbot import locks + + db_lock = locks.MasterLock("database") + build_lock = locks.SlaveLock("slave_builds", + maxCount = 1, + maxCountForSlave = { 'fast': 3, 'new': 2 }) + + After importing locks from buildbot, `db_lock' is defined to be a +master lock. The `"database"' string is used for uniquely identifying +the lock. At the next line, a slave lock called `build_lock' is +created. It is identified by the `"slave_builds"' string. Since the +requirements of the lock are a bit more complicated, two optional +arguments are also specified. The `maxCount' parameter sets the +default limit for builds in counting mode to `1'. For the slave +called `'fast'' however, we want to have at most three builds, and +for the slave called `'new'' the upper limit is two builds running at +the same time. + + The next step is using the locks in builds. Buildbot allows a +lock to be used during an entire build (from beginning to end), or +only during a single build step. In the latter case, the lock is +claimed for use just before the step starts, and released again when +the step ends. To prevent deadlocks,(2) it is not possible to claim +or release locks at other times. + + To use locks, you should add them with a `locks' argument. Each +use of a lock is either in counting mode (that is, possibly shared +with other builds) or in exclusive mode. A build or build step +proceeds only when it has acquired all locks. If a build or step +needs a lot of locks, it may be starved(3) by other builds that need +fewer locks. + + To illustrate use of locks, a few examples. + + from buildbot import locks + from buildbot.steps import source, shell + from buildbot.process import factory + + db_lock = locks.MasterLock("database") + build_lock = locks.SlaveLock("slave_builds", + maxCount = 1, + maxCountForSlave = { 'fast': 3, 'new': 2 }) + + f = factory.BuildFactory() + f.addStep(source.SVN(svnurl="http://example.org/svn/Trunk")) + f.addStep(shell.ShellCommand(command="make all")) + f.addStep(shell.ShellCommand(command="make test", + locks=[db_lock.access('exclusive')])) + + b1 = {'name': 'full1', 'slavename': 'fast', 'builddir': 'f1', 'factory': f, + 'locks': [build_lock.access('counting')] } + + b2 = {'name': 'full2', 'slavename': 'new', 'builddir': 'f2', 'factory': f. + 'locks': [build_lock.access('counting')] } + + b3 = {'name': 'full3', 'slavename': 'old', 'builddir': 'f3', 'factory': f. + 'locks': [build_lock.access('counting')] } + + b4 = {'name': 'full4', 'slavename': 'other', 'builddir': 'f4', 'factory': f. + 'locks': [build_lock.access('counting')] } + + c['builders'] = [b1, b2, b3, b4] + + Here we have four slaves `b1', `b2', `b3', and `b4'. Each slave +performs the same checkout, make, and test build step sequence. We +want to enforce that at most one test step is executed between all +slaves due to restrictions with the data base server. This is done by +adding the `locks=' parameter with the third step. It takes a list of +locks with their access mode. In this case only the `db_lock' is +needed. The exclusive access mode is used to ensure there is at most +one slave that executes the test step. + + In addition to exclusive accessing the data base, we also want +slaves to stay responsive even under the load of a large number of +builds being triggered. For this purpose, the slave lock called +`build_lock' is defined. Since the restraint holds for entire builds, +the lock is specified in the builder with `'locks': +[build_lock.access('counting')]'. + + ---------- Footnotes ---------- + + (1) See http://en.wikipedia.org/wiki/Read/write_lock_pattern for +more information. + + (2) Deadlock is the situation where two or more slaves each hold a +lock in exclusive mode, and in addition want to claim the lock held by +the other slave exclusively as well. Since locks allow at most one +exclusive user, both slaves will wait forever. + + (3) Starving is the situation that only a few locks are available, +and they are immediately grabbed by another build. As a result, it +may take a long time before all locks needed by the starved build are +free at the same time. + + +File: buildbot.info, Node: Build Factories, Prev: Interlocks, Up: Build Process + +6.3 Build Factories +=================== + +Each Builder is equipped with a "build factory", which is responsible +for producing the actual `Build' objects that perform each build. +This factory is created in the configuration file, and attached to a +Builder through the `factory' element of its dictionary. + + The standard `BuildFactory' object creates `Build' objects by +default. These Builds will each execute a collection of BuildSteps in +a fixed sequence. Each step can affect the results of the build, but +in general there is little intelligence to tie the different steps +together. You can create subclasses of `Build' to implement more +sophisticated build processes, and then use a subclass of +`BuildFactory' (or simply set the `buildClass' attribute) to create +instances of your new Build subclass. + +* Menu: + +* BuildStep Objects:: +* BuildFactory:: +* Process-Specific build factories:: + + +File: buildbot.info, Node: BuildStep Objects, Next: BuildFactory, Prev: Build Factories, Up: Build Factories + +6.3.1 BuildStep Objects +----------------------- + +The steps used by these builds are all subclasses of `BuildStep'. +The standard ones provided with Buildbot are documented later, *Note +Build Steps::. You can also write your own subclasses to use in +builds. + + The basic behavior for a `BuildStep' is to: + + * run for a while, then stop + + * possibly invoke some RemoteCommands on the attached build slave + + * possibly produce a set of log files + + * finish with a status described by one of four values defined in + buildbot.status.builder: SUCCESS, WARNINGS, FAILURE, SKIPPED + + * provide a list of short strings to describe the step + + * define a color (generally green, orange, or red) with which the + step should be displayed + + More sophisticated steps may produce additional information and +provide it to later build steps, or store it in the factory to provide +to later builds. + +* Menu: + +* BuildFactory Attributes:: +* Quick builds:: + + +File: buildbot.info, Node: BuildFactory, Next: Process-Specific build factories, Prev: BuildStep Objects, Up: Build Factories + +6.3.2 BuildFactory +------------------ + +The default `BuildFactory', provided in the +`buildbot.process.factory' module, contains an internal list of +"BuildStep specifications": a list of `(step_class, kwargs)' tuples +for each. These specification tuples are constructed when the config +file is read, by asking the instances passed to `addStep' for their +subclass and arguments. + + When asked to create a Build, the `BuildFactory' puts a copy of +the list of step specifications into the new Build object. When the +Build is actually started, these step specifications are used to +create the actual set of BuildSteps, which are then executed one at a +time. This serves to give each Build an independent copy of each step. +For example, a build which consists of a CVS checkout followed by a +`make build' would be constructed as follows: + + from buildbot.steps import source, shell + from buildbot.process import factory + + f = factory.BuildFactory() + f.addStep(source.CVS(cvsroot=CVSROOT, cvsmodule="project", mode="update")) + f.addStep(shell.Compile(command=["make", "build"])) + + (To support config files from buildbot-0.7.5 and earlier, +`addStep' also accepts the `f.addStep(shell.Compile, +command=["make","build"])' form, although its use is discouraged +because then the `Compile' step doesn't get to validate or complain +about its arguments until build time. The modern pass-by-instance +approach allows this validation to occur while the config file is +being loaded, where the admin has a better chance of noticing +problems). + + It is also possible to pass a list of steps into the +`BuildFactory' when it is created. Using `addStep' is usually +simpler, but there are cases where is is more convenient to create +the list of steps ahead of time.: + + from buildbot.steps import source, shell + from buildbot.process import factory + + all_steps = [source.CVS(cvsroot=CVSROOT, cvsmodule="project", mode="update"), + shell.Compile(command=["make", "build"]), + ] + f = factory.BuildFactory(all_steps) + + Each step can affect the build process in the following ways: + + * If the step's `haltOnFailure' attribute is True, then a failure + in the step (i.e. if it completes with a result of FAILURE) will + cause the whole build to be terminated immediately: no further + steps will be executed, with the exception of steps with + `alwaysRun' set to True. `haltOnFailure' is useful for setup + steps upon which the rest of the build depends: if the CVS + checkout or `./configure' process fails, there is no point in + trying to compile or test the resulting tree. + + * If the step's `alwaysRun' attribute is True, then it will always + be run, regardless of if previous steps have failed. This is + useful for cleanup steps that should always be run to return the + build directory or build slave into a good state. + + * If the `flunkOnFailure' or `flunkOnWarnings' flag is set, then a + result of FAILURE or WARNINGS will mark the build as a whole as + FAILED. However, the remaining steps will still be executed. + This is appropriate for things like multiple testing steps: a + failure in any one of them will indicate that the build has + failed, however it is still useful to run them all to completion. + + * Similarly, if the `warnOnFailure' or `warnOnWarnings' flag is + set, then a result of FAILURE or WARNINGS will mark the build as + having WARNINGS, and the remaining steps will still be executed. + This may be appropriate for certain kinds of optional build or + test steps. For example, a failure experienced while building + documentation files should be made visible with a WARNINGS + result but not be serious enough to warrant marking the whole + build with a FAILURE. + + + In addition, each Step produces its own results, may create +logfiles, etc. However only the flags described above have any effect +on the build as a whole. + + The pre-defined BuildSteps like `CVS' and `Compile' have +reasonably appropriate flags set on them already. For example, without +a source tree there is no point in continuing the build, so the `CVS' +class has the `haltOnFailure' flag set to True. Look in +`buildbot/steps/*.py' to see how the other Steps are marked. + + Each Step is created with an additional `workdir' argument that +indicates where its actions should take place. This is specified as a +subdirectory of the slave builder's base directory, with a default +value of `build'. This is only implemented as a step argument (as +opposed to simply being a part of the base directory) because the +CVS/SVN steps need to perform their checkouts from the parent +directory. + +* Menu: + +* BuildFactory Attributes:: +* Quick builds:: + + +File: buildbot.info, Node: BuildFactory Attributes, Next: Quick builds, Prev: BuildFactory, Up: BuildFactory + +6.3.2.1 BuildFactory Attributes +............................... + +Some attributes from the BuildFactory are copied into each Build. + +`useProgress' + (defaults to True): if True, the buildmaster keeps track of how + long each step takes, so it can provide estimates of how long + future builds will take. If builds are not expected to take a + consistent amount of time (such as incremental builds in which a + random set of files are recompiled or tested each time), this + should be set to False to inhibit progress-tracking. + + + +File: buildbot.info, Node: Quick builds, Prev: BuildFactory Attributes, Up: BuildFactory + +6.3.2.2 Quick builds +.................... + +The difference between a "full build" and a "quick build" is that +quick builds are generally done incrementally, starting with the tree +where the previous build was performed. That simply means that the +source-checkout step should be given a `mode='update'' flag, to do +the source update in-place. + + In addition to that, the `useProgress' flag should be set to +False. Incremental builds will (or at least the ought to) compile as +few files as necessary, so they will take an unpredictable amount of +time to run. Therefore it would be misleading to claim to predict how +long the build will take. + + +File: buildbot.info, Node: Process-Specific build factories, Prev: BuildFactory, Up: Build Factories + +6.3.3 Process-Specific build factories +-------------------------------------- + +Many projects use one of a few popular build frameworks to simplify +the creation and maintenance of Makefiles or other compilation +structures. Buildbot provides several pre-configured BuildFactory +subclasses which let you build these projects with a minimum of fuss. + +* Menu: + +* GNUAutoconf:: +* CPAN:: +* Python distutils:: +* Python/Twisted/trial projects:: + + +File: buildbot.info, Node: GNUAutoconf, Next: CPAN, Prev: Process-Specific build factories, Up: Process-Specific build factories + +6.3.3.1 GNUAutoconf +................... + +GNU Autoconf (http://www.gnu.org/software/autoconf/) is a software +portability tool, intended to make it possible to write programs in C +(and other languages) which will run on a variety of UNIX-like +systems. Most GNU software is built using autoconf. It is frequently +used in combination with GNU automake. These tools both encourage a +build process which usually looks like this: + + % CONFIG_ENV=foo ./configure --with-flags + % make all + % make check + # make install + + (except of course the Buildbot always skips the `make install' +part). + + The Buildbot's `buildbot.process.factory.GNUAutoconf' factory is +designed to build projects which use GNU autoconf and/or automake. The +configuration environment variables, the configure flags, and command +lines used for the compile and test are all configurable, in general +the default values will be suitable. + + Example: + + # use the s() convenience function defined earlier + f = factory.GNUAutoconf(source=s(step.SVN, svnurl=URL, mode="copy"), + flags=["--disable-nls"]) + + Required Arguments: + +`source' + This argument must be a step specification tuple that provides a + BuildStep to generate the source tree. + + Optional Arguments: + +`configure' + The command used to configure the tree. Defaults to + `./configure'. Accepts either a string or a list of shell argv + elements. + +`configureEnv' + The environment used for the initial configuration step. This + accepts a dictionary which will be merged into the buildslave's + normal environment. This is commonly used to provide things like + `CFLAGS="-O2 -g"' (to turn off debug symbols during the compile). + Defaults to an empty dictionary. + +`configureFlags' + A list of flags to be appended to the argument list of the + configure command. This is commonly used to enable or disable + specific features of the autoconf-controlled package, like + `["--without-x"]' to disable windowing support. Defaults to an + empty list. + +`compile' + this is a shell command or list of argv values which is used to + actually compile the tree. It defaults to `make all'. If set to + None, the compile step is skipped. + +`test' + this is a shell command or list of argv values which is used to + run the tree's self-tests. It defaults to `make check'. If set to + None, the test step is skipped. + + + +File: buildbot.info, Node: CPAN, Next: Python distutils, Prev: GNUAutoconf, Up: Process-Specific build factories + +6.3.3.2 CPAN +............ + +Most Perl modules available from the CPAN (http://www.cpan.org/) +archive use the `MakeMaker' module to provide configuration, build, +and test services. The standard build routine for these modules looks +like: + + % perl Makefile.PL + % make + % make test + # make install + + (except again Buildbot skips the install step) + + Buildbot provides a `CPAN' factory to compile and test these +projects. + + Arguments: +`source' + (required): A step specification tuple, like that used by + GNUAutoconf. + +`perl' + A string which specifies the `perl' executable to use. Defaults + to just `perl'. + + + +File: buildbot.info, Node: Python distutils, Next: Python/Twisted/trial projects, Prev: CPAN, Up: Process-Specific build factories + +6.3.3.3 Python distutils +........................ + +Most Python modules use the `distutils' package to provide +configuration and build services. The standard build process looks +like: + + % python ./setup.py build + % python ./setup.py install + + Unfortunately, although Python provides a standard unit-test +framework named `unittest', to the best of my knowledge `distutils' +does not provide a standardized target to run such unit tests. (Please +let me know if I'm wrong, and I will update this factory.) + + The `Distutils' factory provides support for running the build +part of this process. It accepts the same `source=' parameter as the +other build factories. + + Arguments: +`source' + (required): A step specification tuple, like that used by + GNUAutoconf. + +`python' + A string which specifies the `python' executable to use. Defaults + to just `python'. + +`test' + Provides a shell command which runs unit tests. This accepts + either a string or a list. The default value is None, which + disables the test step (since there is no common default command + to run unit tests in distutils modules). + + + +File: buildbot.info, Node: Python/Twisted/trial projects, Prev: Python distutils, Up: Process-Specific build factories + +6.3.3.4 Python/Twisted/trial projects +..................................... + +Twisted provides a unit test tool named `trial' which provides a few +improvements over Python's built-in `unittest' module. Many python +projects which use Twisted for their networking or application +services also use trial for their unit tests. These modules are +usually built and tested with something like the following: + + % python ./setup.py build + % PYTHONPATH=build/lib.linux-i686-2.3 trial -v PROJECTNAME.test + % python ./setup.py install + + Unfortunately, the `build/lib' directory into which the +built/copied .py files are placed is actually architecture-dependent, +and I do not yet know of a simple way to calculate its value. For many +projects it is sufficient to import their libraries "in place" from +the tree's base directory (`PYTHONPATH=.'). + + In addition, the PROJECTNAME value where the test files are +located is project-dependent: it is usually just the project's +top-level library directory, as common practice suggests the unit test +files are put in the `test' sub-module. This value cannot be guessed, +the `Trial' class must be told where to find the test files. + + The `Trial' class provides support for building and testing +projects which use distutils and trial. If the test module name is +specified, trial will be invoked. The library path used for testing +can also be set. + + One advantage of trial is that the Buildbot happens to know how to +parse trial output, letting it identify which tests passed and which +ones failed. The Buildbot can then provide fine-grained reports about +how many tests have failed, when individual tests fail when they had +been passing previously, etc. + + Another feature of trial is that you can give it a series of source +.py files, and it will search them for special `test-case-name' tags +that indicate which test cases provide coverage for that file. Trial +can then run just the appropriate tests. This is useful for quick +builds, where you want to only run the test cases that cover the +changed functionality. + + Arguments: +`source' + (required): A step specification tuple, like that used by + GNUAutoconf. + +`buildpython' + A list (argv array) of strings which specifies the `python' + executable to use when building the package. Defaults to just + `['python']'. It may be useful to add flags here, to supress + warnings during compilation of extension modules. This list is + extended with `['./setup.py', 'build']' and then executed in a + ShellCommand. + +`testpath' + Provides a directory to add to `PYTHONPATH' when running the unit + tests, if tests are being run. Defaults to `.' to include the + project files in-place. The generated build library is frequently + architecture-dependent, but may simply be `build/lib' for + pure-python modules. + +`trialpython' + Another list of strings used to build the command that actually + runs trial. This is prepended to the contents of the `trial' + argument below. It may be useful to add `-W' flags here to + supress warnings that occur while tests are being run. Defaults + to an empty list, meaning `trial' will be run without an explicit + interpreter, which is generally what you want if you're using + `/usr/bin/trial' instead of, say, the `./bin/trial' that lives + in the Twisted source tree. + +`trial' + provides the name of the `trial' command. It is occasionally + useful to use an alternate executable, such as `trial2.2' which + might run the tests under an older version of Python. Defaults to + `trial'. + +`tests' + Provides a module name or names which contain the unit tests for + this project. Accepts a string, typically `PROJECTNAME.test', or + a list of strings. Defaults to None, indicating that no tests + should be run. You must either set this or `useTestCaseNames' to + do anyting useful with the Trial factory. + +`useTestCaseNames' + Tells the Step to provide the names of all changed .py files to + trial, so it can look for test-case-name tags and run just the + matching test cases. Suitable for use in quick builds. Defaults + to False. + +`randomly' + If `True', tells Trial (with the `--random=0' argument) to run + the test cases in random order, which sometimes catches subtle + inter-test dependency bugs. Defaults to `False'. + +`recurse' + If `True', tells Trial (with the `--recurse' argument) to look + in all subdirectories for additional test cases. It isn't clear + to me how this works, but it may be useful to deal with the + unknown-PROJECTNAME problem described above, and is currently + used in the Twisted buildbot to accomodate the fact that test + cases are now distributed through multiple + twisted.SUBPROJECT.test directories. + + + Unless one of `trialModule' or `useTestCaseNames' are set, no +tests will be run. + + Some quick examples follow. Most of these examples assume that the +target python code (the "code under test") can be reached directly +from the root of the target tree, rather than being in a `lib/' +subdirectory. + + # Trial(source, tests="toplevel.test") does: + # python ./setup.py build + # PYTHONPATH=. trial -to toplevel.test + + # Trial(source, tests=["toplevel.test", "other.test"]) does: + # python ./setup.py build + # PYTHONPATH=. trial -to toplevel.test other.test + + # Trial(source, useTestCaseNames=True) does: + # python ./setup.py build + # PYTHONPATH=. trial -to --testmodule=foo/bar.py.. (from Changes) + + # Trial(source, buildpython=["python2.3", "-Wall"], tests="foo.tests"): + # python2.3 -Wall ./setup.py build + # PYTHONPATH=. trial -to foo.tests + + # Trial(source, trialpython="python2.3", trial="/usr/bin/trial", + # tests="foo.tests") does: + # python2.3 -Wall ./setup.py build + # PYTHONPATH=. python2.3 /usr/bin/trial -to foo.tests + + # For running trial out of the tree being tested (only useful when the + # tree being built is Twisted itself): + # Trial(source, trialpython=["python2.3", "-Wall"], trial="./bin/trial", + # tests="foo.tests") does: + # python2.3 -Wall ./setup.py build + # PYTHONPATH=. python2.3 -Wall ./bin/trial -to foo.tests + + If the output directory of `./setup.py build' is known, you can +pull the python code from the built location instead of the source +directories. This should be able to handle variations in where the +source comes from, as well as accomodating binary extension modules: + + # Trial(source,tests="toplevel.test",testpath='build/lib.linux-i686-2.3') + # does: + # python ./setup.py build + # PYTHONPATH=build/lib.linux-i686-2.3 trial -to toplevel.test + + +File: buildbot.info, Node: Status Delivery, Next: Command-line tool, Prev: Build Process, Up: Top + +7 Status Delivery +***************** + +More details are available in the docstrings for each class, use a +command like `pydoc buildbot.status.html.WebStatus' to see them. +Most status delivery objects take a `categories=' argument, which can +contain a list of "category" names: in this case, it will only show +status for Builders that are in one of the named categories. + + (implementor's note: each of these objects should be a +service.MultiService which will be attached to the BuildMaster object +when the configuration is processed. They should use +`self.parent.getStatus()' to get access to the top-level IStatus +object, either inside `startService' or later. They may call +`status.subscribe()' in `startService' to receive notifications of +builder events, in which case they must define `builderAdded' and +related methods. See the docstrings in `buildbot/interfaces.py' for +full details.) + +* Menu: + +* WebStatus:: +* MailNotifier:: +* IRC Bot:: +* PBListener:: +* Writing New Status Plugins:: + + +File: buildbot.info, Node: WebStatus, Next: MailNotifier, Prev: Status Delivery, Up: Status Delivery + +7.1 WebStatus +============= + +The `buildbot.status.html.WebStatus' status target runs a small web +server inside the buildmaster. You can point a browser at this web +server and retrieve information about every build the buildbot knows +about, as well as find out what the buildbot is currently working on. + + The first page you will see is the "Welcome Page", which contains +links to all the other useful pages. This page is simply served from +the `public_html/index.html' file in the buildmaster's base +directory, where it is created by the `buildbot create-master' +command along with the rest of the buildmaster. + + The most complex resource provided by `WebStatus' is the +"Waterfall Display", which shows a time-based chart of events. This +somewhat-busy display provides detailed information about all steps of +all recent builds, and provides hyperlinks to look at individual build +logs and source changes. By simply reloading this page on a regular +basis, you will see a complete description of everything the buildbot +is currently working on. + + There are also pages with more specialized information. For +example, there is a page which shows the last 20 builds performed by +the buildbot, one line each. Each line is a link to detailed +information about that build. By adding query arguments to the URL +used to reach this page, you can narrow the display to builds that +involved certain branches, or which ran on certain Builders. These +pages are described in great detail below. + + When the buildmaster is created, a subdirectory named +`public_html/' is created in its base directory. By default, +`WebStatus' will serve files from this directory: for example, when a +user points their browser at the buildbot's `WebStatus' URL, they +will see the contents of the `public_html/index.html' file. Likewise, +`public_html/robots.txt', `public_html/buildbot.css', and +`public_html/favicon.ico' are all useful things to have in there. +The first time a buildmaster is created, the `public_html' directory +is populated with some sample files, which you will probably want to +customize for your own project. These files are all static: the +buildbot does not modify them in any way as it serves them to HTTP +clients. + + from buildbot.status.html import WebStatus + c['status'].append(WebStatus(8080)) + + Note that the initial robots.txt file has Disallow lines for all of +the dynamically-generated buildbot pages, to discourage web spiders +and search engines from consuming a lot of CPU time as they crawl +through the entire history of your buildbot. If you are running the +buildbot behind a reverse proxy, you'll probably need to put the +robots.txt file somewhere else (at the top level of the parent web +server), and replace the URL prefixes in it with more suitable values. + + If you would like to use an alternative root directory, add the +`public_html=..' option to the `WebStatus' creation: + + c['status'].append(WebStatus(8080, public_html="/var/www/buildbot")) + + In addition, if you are familiar with twisted.web _Resource +Trees_, you can write code to add additional pages at places inside +this web space. Just use `webstatus.putChild' to place these +resources. + + The following section describes the special URLs and the status +views they provide. + +* Menu: + +* WebStatus Configuration Parameters:: +* Buildbot Web Resources:: +* XMLRPC server:: +* HTML Waterfall:: + + +File: buildbot.info, Node: WebStatus Configuration Parameters, Next: Buildbot Web Resources, Prev: WebStatus, Up: WebStatus + +7.1.1 WebStatus Configuration Parameters +---------------------------------------- + +The most common way to run a `WebStatus' is on a regular TCP port. To +do this, just pass in the TCP port number when you create the +`WebStatus' instance; this is called the `http_port' argument: + + from buildbot.status.html import WebStatus + c['status'].append(WebStatus(8080)) + + The `http_port' argument is actually a "strports specification" +for the port that the web server should listen on. This can be a +simple port number, or a string like `tcp:8080:interface=127.0.0.1' +(to limit connections to the loopback interface, and therefore to +clients running on the same host)(1). + + If instead (or in addition) you provide the `distrib_port' +argument, a twisted.web distributed server will be started either on a +TCP port (if `distrib_port' is like `"tcp:12345"') or more likely on +a UNIX socket (if `distrib_port' is like `"unix:/path/to/socket"'). + + The `distrib_port' option means that, on a host with a +suitably-configured twisted-web server, you do not need to consume a +separate TCP port for the buildmaster's status web page. When the web +server is constructed with `mktap web --user', URLs that point to +`http://host/~username/' are dispatched to a sub-server that is +listening on a UNIX socket at `~username/.twisted-web-pb'. On such a +system, it is convenient to create a dedicated `buildbot' user, then +set `distrib_port' to +`"unix:"+os.path.expanduser("~/.twistd-web-pb")'. This configuration +will make the HTML status page available at `http://host/~buildbot/' +. Suitable URL remapping can make it appear at +`http://host/buildbot/', and the right virtual host setup can even +place it at `http://buildbot.host/' . + + The other `WebStatus' argument is `allowForce'. If set to True, +then the web page will provide a "Force Build" button that allows +visitors to manually trigger builds. This is useful for developers to +re-run builds that have failed because of intermittent problems in +the test suite, or because of libraries that were not installed at +the time of the previous build. You may not wish to allow strangers +to cause a build to run: in that case, set this to False to remove +these buttons. The default value is False. + + ---------- Footnotes ---------- + + (1) It may even be possible to provide SSL access by using a +specification like +`"ssl:12345:privateKey=mykey.pen:certKey=cert.pem"', but this is +completely untested + |