Sophie

Sophie

distrib > Mageia > 6 > armv5tl > by-pkgid > 821bff9b1c6450f83fd56c64b66aa3f7 > files > 173

buildbot-doc-0.8.12-3.mga6.noarch.rpm

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">


<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    
    <title>Buildbot in 5 minutes - a user-contributed tutorial &mdash; Buildbot 0.8.12 documentation</title>
    
    <link rel="stylesheet" href="../_static/agogo.css" type="text/css" />
    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
    
    <script type="text/javascript">
      var DOCUMENTATION_OPTIONS = {
        URL_ROOT:    '../',
        VERSION:     '0.8.12',
        COLLAPSE_INDEX: false,
        FILE_SUFFIX: '.html',
        HAS_SOURCE:  true
      };
    </script>
    <script type="text/javascript" src="../_static/jquery.js"></script>
    <script type="text/javascript" src="../_static/underscore.js"></script>
    <script type="text/javascript" src="../_static/doctools.js"></script>
    <link rel="shortcut icon" href="../_static/buildbot.ico"/>
    <link rel="top" title="Buildbot 0.8.12 documentation" href="../index.html" />
    <link rel="up" title="Further Reading" href="further.html" />
    <link rel="next" title="Buildbot Manual" href="../manual/index.html" />
    <link rel="prev" title="Further Reading" href="further.html" /> 
  </head>
  <body role="document">
    <div class="header-wrapper" role="banner">
      <div class="header">
          <p class="logo"><a href="../index.html">
            <img class="logo" src="../_static/header-text-transparent.png" alt="Logo"/>
          </a></p>
        <div class="headertitle"><a
          href="../index.html">Buildbot 0.8.12 documentation</a></div>
        <div class="rel" role="navigation" aria-label="related navigation">
          <a href="further.html" title="Further Reading"
             accesskey="P">previous</a> |
          <a href="../manual/index.html" title="Buildbot Manual"
             accesskey="N">next</a> |
          <a href="../py-modindex.html" title="Python Module Index"
             >modules</a> |
          <a href="../genindex.html" title="General Index"
             accesskey="I">index</a>
        </div>
       </div>
    </div>

    <div class="content-wrapper">
      <div class="content">
        <div class="document">
            
      <div class="documentwrapper">
        <div class="bodywrapper">
          <div class="body" role="main">
            
  <div class="section" id="buildbot-in-5-minutes-a-user-contributed-tutorial">
<span id="fiveminutes"></span><h1>Buildbot in 5 minutes - a user-contributed tutorial<a class="headerlink" href="#buildbot-in-5-minutes-a-user-contributed-tutorial" title="Permalink to this headline">¶</a></h1>
<p>(Ok, maybe 10.)</p>
<p>Buildbot is really an excellent piece of software, however it can be a bit confusing for a newcomer (like me when I first started looking at it).
Typically, at first sight it looks like a bunch of complicated concepts that make no sense and whose relationships with each other are unclear.
After some time and some reread, it all slowly starts to be more and more meaningful, until you finally say &quot;oh!&quot; and things start to make sense.
Once you get there, you realize that the documentation is great, but only if you already know what it's about.</p>
<p>This is what happened to me, at least.
Here I'm going to (try to) explain things in a way that would have helped me more as a newcomer.
The approach I'm taking is more or less the reverse of that used by the documentation, that is, I'm going to start from the components that do the actual work (the builders) and go up the chain from there up to change sources.
I hope purists will forgive this unorthodoxy.
Here I'm trying to clarify the concepts only, and will not go into the details of each object or property; the documentation explains those quite well.</p>
<div class="section" id="installation">
<h2>Installation<a class="headerlink" href="#installation" title="Permalink to this headline">¶</a></h2>
<p>I won't cover the installation; both buildbot master and slave are available as packages for the major distributions, and in any case the instructions in the official documentation are fine.
This document will refer to buildbot 0.8.5 which was current at the time of writing, but hopefully the concepts are not too different in other versions.
All the code shown is of course python code, and has to be included in the master.cfg master configuration file.</p>
<p>We won't cover the basic things such as how to define the slaves, project names, or other administrative information that is contained in that file; for that, again the official documentation is fine.</p>
</div>
<div class="section" id="builders-the-workhorses">
<h2>Builders: the workhorses<a class="headerlink" href="#builders-the-workhorses" title="Permalink to this headline">¶</a></h2>
<p>Since buildbot is a tool whose goal is the automation of software builds, it makes sense to me to start from where we tell buildbot how to build our software: the <cite>builder</cite> (or builders, since there can be more than one).</p>
<p>Simply put, a builder is an element that is in charge of performing some action or sequence of actions, normally something related to building software (for example, checking out the source, or <code class="docutils literal"><span class="pre">make</span> <span class="pre">all</span></code>), but it can also run arbitrary commands.</p>
<p>A builder is configured with a list of slaves that it can use to carry out its task.
The other fundamental piece of information that a builder needs is, of course, the list of things it has to do (which will normally run on the chosen slave).
In Buildbot, this list of things is represented as a <code class="docutils literal"><span class="pre">BuildFactory</span></code> object, which is essentially a sequence of steps, each one defining a certain operation or command.</p>
<p>Enough talk, let's see an example.
For this example, we are going to assume that our super software project can be built using a simple <code class="docutils literal"><span class="pre">make</span> <span class="pre">all</span></code>, and there is another target <code class="docutils literal"><span class="pre">make</span> <span class="pre">packages</span></code> that creates rpm, deb and tgz packages of the binaries.
In the real world things are usually more complex (for example there may be a <code class="docutils literal"><span class="pre">configure</span></code> step, or multiple targets), but the concepts are the same; it will just be a matter of adding more steps to a builder, or creating multiple builders, although sometimes the resulting builders can be quite complex.</p>
<p>So to perform a manual build of our project we would type this from the command line (assuming we are at the root of the local copy of the repository):</p>
<div class="highlight-bash"><div class="highlight"><pre><span></span>$ make clean    <span class="c1"># clean remnants of previous builds</span>
...
$ svn update
...
$ make all
...
$ make packages
...
<span class="c1"># optional but included in the example: copy packages to some central machine</span>
$ scp packages/*.rpm packages/*.deb packages/*.tgz someuser@somehost:/repository
...
</pre></div>
</div>
<p>Here we're assuming the repository is SVN, but again the concepts are the same with git, mercurial or any other VCS.</p>
<p>Now, to automate this, we create a builder where each step is one of the commands we typed above.
A step can be a shell command object, or a dedicated object that checks out the source code (there are various types for different repositories, see the docs for more info), or yet something else:</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">buildbot.process.factory</span> <span class="k">import</span> <span class="n">BuildFactory</span>
<span class="kn">from</span> <span class="nn">buildbot.steps.source</span> <span class="k">import</span> <span class="n">SVN</span>
<span class="kn">from</span> <span class="nn">buildbot.steps.shell</span> <span class="k">import</span> <span class="n">ShellCommand</span>

<span class="c1"># first, let&#39;s create the individual step objects</span>

<span class="c1"># step 1: make clean; this fails if the slave has no local copy, but</span>
<span class="c1"># is harmless and will only happen the first time</span>
<span class="n">makeclean</span> <span class="o">=</span> <span class="n">ShellCommand</span><span class="p">(</span><span class="n">name</span> <span class="o">=</span> <span class="s2">&quot;make clean&quot;</span><span class="p">,</span>
                         <span class="n">command</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;make&quot;</span><span class="p">,</span> <span class="s2">&quot;clean&quot;</span><span class="p">],</span>
                         <span class="n">description</span> <span class="o">=</span> <span class="s2">&quot;make clean&quot;</span><span class="p">)</span>

<span class="c1"># step 2: svn update (here updates trunk, see the docs for more</span>
<span class="c1"># on how to update a branch, or make it more generic).</span>
<span class="n">checkout</span> <span class="o">=</span> <span class="n">SVN</span><span class="p">(</span><span class="n">baseURL</span> <span class="o">=</span> <span class="s1">&#39;svn://myrepo/projects/coolproject/trunk&#39;</span><span class="p">,</span>
               <span class="n">mode</span> <span class="o">=</span> <span class="s2">&quot;update&quot;</span><span class="p">,</span>
               <span class="n">username</span> <span class="o">=</span> <span class="s2">&quot;foo&quot;</span><span class="p">,</span>
               <span class="n">password</span> <span class="o">=</span> <span class="s2">&quot;bar&quot;</span><span class="p">,</span>
               <span class="n">haltOnFailure</span> <span class="o">=</span> <span class="kc">True</span> <span class="p">)</span>

<span class="c1"># step 3: make all</span>
<span class="n">makeall</span> <span class="o">=</span> <span class="n">ShellCommand</span><span class="p">(</span><span class="n">name</span> <span class="o">=</span> <span class="s2">&quot;make all&quot;</span><span class="p">,</span>
                       <span class="n">command</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;make&quot;</span><span class="p">,</span> <span class="s2">&quot;all&quot;</span><span class="p">],</span>
                       <span class="n">haltOnFailure</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
                       <span class="n">description</span> <span class="o">=</span> <span class="s2">&quot;make all&quot;</span><span class="p">)</span>

<span class="c1"># step 4: make packages</span>
<span class="n">makepackages</span> <span class="o">=</span> <span class="n">ShellCommand</span><span class="p">(</span><span class="n">name</span> <span class="o">=</span> <span class="s2">&quot;make packages&quot;</span><span class="p">,</span>
                            <span class="n">command</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;make&quot;</span><span class="p">,</span> <span class="s2">&quot;packages&quot;</span><span class="p">],</span>
                            <span class="n">haltOnFailure</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
                            <span class="n">description</span> <span class="o">=</span> <span class="s2">&quot;make packages&quot;</span><span class="p">)</span>

<span class="c1"># step 5: upload packages to central server. This needs passwordless ssh</span>
<span class="c1"># from the slave to the server (set it up in advance as part of slave setup)</span>
<span class="n">uploadpackages</span> <span class="o">=</span> <span class="n">ShellCommand</span><span class="p">(</span><span class="n">name</span> <span class="o">=</span> <span class="s2">&quot;upload packages&quot;</span><span class="p">,</span>
                              <span class="n">description</span> <span class="o">=</span> <span class="s2">&quot;upload packages&quot;</span><span class="p">,</span>
                              <span class="n">command</span> <span class="o">=</span> <span class="s2">&quot;scp packages/*.rpm packages/*.deb packages/*.tgz someuser@somehost:/repository&quot;</span><span class="p">,</span>
                              <span class="n">haltOnFailure</span> <span class="o">=</span> <span class="kc">True</span><span class="p">)</span>

<span class="c1"># create the build factory and add the steps to it</span>
<span class="n">f_simplebuild</span> <span class="o">=</span> <span class="n">BuildFactory</span><span class="p">()</span>
<span class="n">f_simplebuild</span><span class="o">.</span><span class="n">addStep</span><span class="p">(</span><span class="n">makeclean</span><span class="p">)</span>
<span class="n">f_simplebuild</span><span class="o">.</span><span class="n">addStep</span><span class="p">(</span><span class="n">checkout</span><span class="p">)</span>
<span class="n">f_simplebuild</span><span class="o">.</span><span class="n">addStep</span><span class="p">(</span><span class="n">makeall</span><span class="p">)</span>
<span class="n">f_simplebuild</span><span class="o">.</span><span class="n">addStep</span><span class="p">(</span><span class="n">makepackages</span><span class="p">)</span>
<span class="n">f_simplebuild</span><span class="o">.</span><span class="n">addStep</span><span class="p">(</span><span class="n">uploadpackages</span><span class="p">)</span>

<span class="c1"># finally, declare the list of builders. In this case, we only have one builder</span>
<span class="n">c</span><span class="p">[</span><span class="s1">&#39;builders&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span>
    <span class="n">BuilderConfig</span><span class="p">(</span><span class="n">name</span> <span class="o">=</span> <span class="s2">&quot;simplebuild&quot;</span><span class="p">,</span> <span class="n">slavenames</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;slave1&#39;</span><span class="p">,</span> <span class="s1">&#39;slave2&#39;</span><span class="p">,</span> <span class="s1">&#39;slave3&#39;</span><span class="p">],</span> <span class="n">factory</span> <span class="o">=</span> <span class="n">f_simplebuild</span><span class="p">)</span>
<span class="p">]</span>
</pre></div>
</div>
<p>So our builder is called <code class="docutils literal"><span class="pre">simplebuild</span></code> and can run on either of <code class="docutils literal"><span class="pre">slave1</span></code>, <code class="docutils literal"><span class="pre">slave2</span></code> and <code class="docutils literal"><span class="pre">slave3</span></code>.
If our repository has other branches besides trunk, we could create another one or more builders to build them; in the example, only the checkout step would be different, in that it would need to check out the specific branch.
Depending on how exactly those branches have to be built, the shell commands may be recycled, or new ones would have to be created if they are different in the branch.
You get the idea.
The important thing is that all the builders be named differently and all be added to the <code class="docutils literal"><span class="pre">c['builders']</span></code> value (as can be seen above, it is a list of <code class="docutils literal"><span class="pre">BuilderConfig</span></code> objects).</p>
<p>Of course the type and number of steps will vary depending on the goal; for example, to just check that a commit doesn't break the build, we could include just up to the <code class="docutils literal"><span class="pre">make</span> <span class="pre">all</span></code> step.
Or we could have a builder that performs a more thorough test by also doing <code class="docutils literal"><span class="pre">make</span> <span class="pre">test</span></code> or other targets.
You get the idea.
Note that at each step except the very first we use <code class="docutils literal"><span class="pre">haltOnFailure</span> <span class="pre">=</span> <span class="pre">True</span></code> because it would not make sense to execute a step if the previous one failed (ok, it wouldn't be needed for the last step, but it's harmless and protects us if one day we add another step after it).</p>
</div>
<div class="section" id="schedulers">
<h2>Schedulers<a class="headerlink" href="#schedulers" title="Permalink to this headline">¶</a></h2>
<p>Now this is all nice and dandy, but who tells the builder (or builders) to run, and when?
This is the job of the <cite>scheduler</cite>, which is a fancy name for an element that waits for some event to happen, and when it does, based on that information decides whether and when to run a builder (and which one or ones).
There can be more than one scheduler.
I'm being purposely vague here because the possibilities are almost endless and highly dependent on the actual setup, build purposes, source repository layout and other elements.</p>
<p>So a scheduler needs to be configured with two main pieces of information: on one hand, which events to react to, and on the other hand, which builder or builders to trigger when those events are detected.
(It's more complex than that, but if you understand this, you can get the rest of the details from the docs).</p>
<p>A simple type of scheduler may be a periodic scheduler: when a configurable amount of time has passed, run a certain builder (or builders).
In our example, that's how we would trigger a build every hour:</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">buildbot.schedulers.timed</span> <span class="k">import</span> <span class="n">Periodic</span>

<span class="c1"># define the periodic scheduler</span>
<span class="n">hourlyscheduler</span> <span class="o">=</span> <span class="n">Periodic</span><span class="p">(</span><span class="n">name</span> <span class="o">=</span> <span class="s2">&quot;hourly&quot;</span><span class="p">,</span>
                           <span class="n">builderNames</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;simplebuild&quot;</span><span class="p">],</span>
                           <span class="n">periodicBuildTimer</span> <span class="o">=</span> <span class="mi">3600</span><span class="p">)</span>

<span class="c1"># define the available schedulers</span>
<span class="n">c</span><span class="p">[</span><span class="s1">&#39;schedulers&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span> <span class="n">hourlyscheduler</span> <span class="p">]</span>
</pre></div>
</div>
<p>That's it.
Every hour this <code class="docutils literal"><span class="pre">hourly</span></code> scheduler will run the <code class="docutils literal"><span class="pre">simplebuild</span></code> builder.
If we have more than one builder that we want to run every hour, we can just add them to the <code class="docutils literal"><span class="pre">builderNames</span></code> list when defining the scheduler and they will all be run.
Or since multiple scheduler are allowed, other schedulers can be defined and added to <code class="docutils literal"><span class="pre">c['schedulers']</span></code> in the same way.</p>
<p>Other types of schedulers exist; in particular, there are schedulers that can be more dynamic than the periodic one.
The typical dynamic scheduler is one that learns about changes in a source repository (generally because some developer checks in some change), and triggers one or more builders in response to those changes.
Let's assume for now that the scheduler &quot;magically&quot; learns about changes in the repository (more about this later); here's how we would define it:</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">buildbot.schedulers.basic</span> <span class="k">import</span> <span class="n">SingleBranchScheduler</span>
<span class="kn">from</span> <span class="nn">buildbot.changes</span> <span class="k">import</span> <span class="nb">filter</span>

<span class="c1"># define the dynamic scheduler</span>
<span class="n">trunkchanged</span> <span class="o">=</span> <span class="n">SingleBranchScheduler</span><span class="p">(</span><span class="n">name</span> <span class="o">=</span> <span class="s2">&quot;trunkchanged&quot;</span><span class="p">,</span>
                                     <span class="n">change_filter</span> <span class="o">=</span> <span class="nb">filter</span><span class="o">.</span><span class="n">ChangeFilter</span><span class="p">(</span><span class="n">branch</span> <span class="o">=</span> <span class="kc">None</span><span class="p">),</span>
                                     <span class="n">treeStableTimer</span> <span class="o">=</span> <span class="mi">300</span><span class="p">,</span>
                                     <span class="n">builderNames</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;simplebuild&quot;</span><span class="p">])</span>

<span class="c1"># define the available schedulers</span>
<span class="n">c</span><span class="p">[</span><span class="s1">&#39;schedulers&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span> <span class="n">trunkchanged</span> <span class="p">]</span>
</pre></div>
</div>
<p>This scheduler receives changes happening to the repository, and among all of them, pays attention to those happening in &quot;trunk&quot; (that's what <code class="docutils literal"><span class="pre">branch</span> <span class="pre">=</span> <span class="pre">None</span></code> means).
In other words, it filters the changes to react only to those it's interested in.
When such changes are detected, and the tree has been quiet for 5 minutes (300 seconds), it runs the <code class="docutils literal"><span class="pre">simplebuild</span></code> builder.
The <code class="docutils literal"><span class="pre">treeStableTimer</span></code> helps in those situations where commits tend to happen in bursts, which would otherwise result in multiple build requests queuing up.</p>
<p>What if we want to act on two branches (say, trunk and 7.2)?
First we create two builders, one for each branch (see the builders paragraph above), then we create two dynamic schedulers:</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">buildbot.schedulers.basic</span> <span class="k">import</span> <span class="n">SingleBranchScheduler</span>
<span class="kn">from</span> <span class="nn">buildbot.changes</span> <span class="k">import</span> <span class="nb">filter</span>

<span class="c1"># define the dynamic scheduler for trunk</span>
<span class="n">trunkchanged</span> <span class="o">=</span> <span class="n">SingleBranchScheduler</span><span class="p">(</span><span class="n">name</span> <span class="o">=</span> <span class="s2">&quot;trunkchanged&quot;</span><span class="p">,</span>
                                     <span class="n">change_filter</span> <span class="o">=</span> <span class="nb">filter</span><span class="o">.</span><span class="n">ChangeFilter</span><span class="p">(</span><span class="n">branch</span> <span class="o">=</span> <span class="kc">None</span><span class="p">),</span>
                                     <span class="n">treeStableTimer</span> <span class="o">=</span> <span class="mi">300</span><span class="p">,</span>
                                     <span class="n">builderNames</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;simplebuild-trunk&quot;</span><span class="p">])</span>

<span class="c1"># define the dynamic scheduler for the 7.2 branch</span>
<span class="n">branch72changed</span> <span class="o">=</span> <span class="n">SingleBranchScheduler</span><span class="p">(</span><span class="n">name</span> <span class="o">=</span> <span class="s2">&quot;branch72changed&quot;</span><span class="p">,</span>
                                        <span class="n">change_filter</span> <span class="o">=</span> <span class="nb">filter</span><span class="o">.</span><span class="n">ChangeFilter</span><span class="p">(</span><span class="n">branch</span> <span class="o">=</span> <span class="s1">&#39;branches/7.2&#39;</span><span class="p">),</span>
                                        <span class="n">treeStableTimer</span> <span class="o">=</span> <span class="mi">300</span><span class="p">,</span>
                                        <span class="n">builderNames</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;simplebuild-72&quot;</span><span class="p">])</span>

<span class="c1"># define the available schedulers</span>
<span class="n">c</span><span class="p">[</span><span class="s1">&#39;schedulers&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span> <span class="n">trunkchanged</span><span class="p">,</span> <span class="n">branch72changed</span> <span class="p">]</span>
</pre></div>
</div>
<p>The syntax of the change filter is VCS-dependent (above is for SVN), but again once the idea is clear, the documentation has all the details.
Another feature of the scheduler is that is can be told which changes, within those it's paying attention to, are important and which are not.
For example, there may be a documentation directory in the branch the scheduler is watching, but changes under that directory should not trigger a build of the binary.
This finer filtering is implemented by means of the <code class="docutils literal"><span class="pre">fileIsImportant</span></code> argument to the scheduler (full details in the docs and - alas - in the sources).</p>
</div>
<div class="section" id="change-sources">
<h2>Change sources<a class="headerlink" href="#change-sources" title="Permalink to this headline">¶</a></h2>
<p>Earlier we said that a dynamic scheduler &quot;magically&quot; learns about changes; the final piece of the puzzle are <cite>change sources</cite>, which are precisely the elements in buildbot whose task is to detect changes in the repository and communicate them to the schedulers.
Note that periodic schedulers don't need a change source, since they only depend on elapsed time; dynamic schedulers, on the other hand, do need a change source.</p>
<p>A change source is generally configured with information about a source repository (which is where changes happen); a change source can watch changes at different levels in the hierarchy of the repository, so for example it is possible to watch the whole repository or a subset of it, or just a single branch.
This determines the extent of the information that is passed down to the schedulers.</p>
<p>There are many ways a change source can learn about changes; it can periodically poll the repository for changes, or the VCS can be configured (for example through hook scripts triggered by commits) to push changes into the change source.
While these two methods are probably the most common, they are not the only possibilities; it is possible for example to have a change source detect changes by parsing some email sent to a mailing list when a commit happen, and yet other methods exist.
The manual again has the details.</p>
<p>To complete our example, here's a change source that polls a SVN repository every 2 minutes:</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">buildbot.changes.svnpoller</span> <span class="k">import</span> <span class="n">SVNPoller</span><span class="p">,</span> <span class="n">split_file_branches</span>

<span class="n">svnpoller</span> <span class="o">=</span> <span class="n">SVNPoller</span><span class="p">(</span><span class="n">svnurl</span> <span class="o">=</span> <span class="s2">&quot;svn://myrepo/projects/coolproject&quot;</span><span class="p">,</span>
                      <span class="n">svnuser</span> <span class="o">=</span> <span class="s2">&quot;foo&quot;</span><span class="p">,</span>
                      <span class="n">svnpasswd</span> <span class="o">=</span> <span class="s2">&quot;bar&quot;</span><span class="p">,</span>
                      <span class="n">pollinterval</span> <span class="o">=</span> <span class="mi">120</span><span class="p">,</span>
                      <span class="n">split_file</span> <span class="o">=</span> <span class="n">split_file_branches</span><span class="p">)</span>

<span class="n">c</span><span class="p">[</span><span class="s1">&#39;change_source&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">svnpoller</span>
</pre></div>
</div>
<p>This poller watches the whole &quot;coolproject&quot; section of the repository, so it will detect changes in all the branches.
We could have said:</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">svnurl</span> <span class="o">=</span> <span class="s2">&quot;svn://myrepo/projects/coolproject/trunk&quot;</span>
</pre></div>
</div>
<p>or:</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">svnurl</span> <span class="o">=</span> <span class="s2">&quot;svn://myrepo/projects/coolproject/branches/7.2&quot;</span>
</pre></div>
</div>
<p>to watch only a specific branch.</p>
<p>To watch another project, you need to create another change source -- and you need to filter changes by project.
For instance, when you add a change source watching project 'superproject' to the above example, you need to change:</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">trunkchanged</span> <span class="o">=</span> <span class="n">SingleBranchScheduler</span><span class="p">(</span><span class="n">name</span> <span class="o">=</span> <span class="s2">&quot;trunkchanged&quot;</span><span class="p">,</span>
                                     <span class="n">change_filter</span> <span class="o">=</span> <span class="nb">filter</span><span class="o">.</span><span class="n">ChangeFilter</span><span class="p">(</span><span class="n">branch</span> <span class="o">=</span> <span class="kc">None</span><span class="p">),</span>
                                     <span class="c1"># ...</span>
                                     <span class="p">)</span>
</pre></div>
</div>
<p>to e.g.:</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">trunkchanged</span> <span class="o">=</span> <span class="n">SingleBranchScheduler</span><span class="p">(</span><span class="n">name</span> <span class="o">=</span> <span class="s2">&quot;trunkchanged&quot;</span><span class="p">,</span>
                                     <span class="n">change_filter</span> <span class="o">=</span> <span class="nb">filter</span><span class="o">.</span><span class="n">ChangeFilter</span><span class="p">(</span><span class="n">project</span> <span class="o">=</span> <span class="s2">&quot;coolproject&quot;</span><span class="p">,</span> <span class="n">branch</span> <span class="o">=</span> <span class="kc">None</span><span class="p">),</span>
                                     <span class="c1"># ...</span>
                                     <span class="p">)</span>
</pre></div>
</div>
<p>else coolproject will be built when there's a change in superproject.</p>
<p>Since we're watching more than one branch, we need a method to tell in which branch the change occurred when we detect one.
This is what the split_file argument does, it takes a callable that buildbot will call to do the job.
The split_file_branches function, which comes with buildbot, is designed for exactly this purpose so that's what the example above uses.</p>
<p>And of course this is all SVN-specific, but there are pollers for all the popular VCSs.</p>
<p>But note: if you have many projects, branches, and builders it probably pays to not hardcode all the schedulers and builders in the configuration, but generate them dynamically starting from list of all projects, branches, targets etc.
And using loops to generate all possible combinations (or only the needed ones, depending on the specific setup), as explained in the documentation chapter about <a class="reference internal" href="../manual/customization.html"><span class="doc">Customization</span></a>.</p>
</div>
<div class="section" id="status-targets">
<h2>Status targets<a class="headerlink" href="#status-targets" title="Permalink to this headline">¶</a></h2>
<p>Now that the basics are in place, let's go back to the builders, which is where the real work happens.
<cite>Status targets</cite> are simply the means buildbot uses to inform the world about what's happening, that is, how builders are doing.
There are many status target: a web interface, a mail notifier, an IRC notifier, and others.
They are described fairly well in the manual.</p>
<p>One thing I've found useful is the ability to pass a domain name as the lookup argument to a <code class="docutils literal"><span class="pre">mailNotifier</span></code>, which allows to take an unqualified username as it appears in the SVN change and create a valid email address by appending the given domain name to it:</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">buildbot.status</span> <span class="k">import</span> <span class="n">mail</span>

<span class="c1"># if jsmith commits a change, mail for the build is sent to jsmith@example.org</span>
<span class="n">notifier</span> <span class="o">=</span> <span class="n">mail</span><span class="o">.</span><span class="n">MailNotifier</span><span class="p">(</span><span class="n">fromaddr</span> <span class="o">=</span> <span class="s2">&quot;buildbot@example.org&quot;</span><span class="p">,</span>
                             <span class="n">sendToInterestedUsers</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
                             <span class="n">lookup</span> <span class="o">=</span> <span class="s2">&quot;example.org&quot;</span><span class="p">)</span>
<span class="n">c</span><span class="p">[</span><span class="s1">&#39;status&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">notifier</span><span class="p">)</span>
</pre></div>
</div>
<p>The mail notifier can be customized at will by means of the <code class="docutils literal"><span class="pre">messageFormatter</span></code> argument, which is a function that buildbot calls to format the body of the email, and to which it makes available lots of information about the build.
Here all the details.</p>
</div>
<div class="section" id="conclusion">
<h2>Conclusion<a class="headerlink" href="#conclusion" title="Permalink to this headline">¶</a></h2>
<p>Please note that this article has just scratched the surface; given the complexity of the task of build automation, the possibilities are almost endless.
So there's much, much more to say about buildbot.
However, hopefully this is a preparation step before reading the official manual.
Had I found an explanation as the one above when I was approaching buildbot, I'd have had to read the manual just once, rather than multiple times.
Hope this can help someone else.</p>
<p>(Thanks to Davide Brini for permission to include this tutorial, derived from one he originally posted at <a class="reference external" href="http://backreference.org">http://backreference.org</a>.)</p>
</div>
</div>


          </div>
        </div>
      </div>
        </div>
        <div class="sidebar">
<h3>Table Of Contents</h3>
<ul class="current">
<li class="toctree-l1 current"><a class="reference internal" href="index.html">Buildbot Tutorial</a><ul class="current">
<li class="toctree-l2"><a class="reference internal" href="firstrun.html">First Run</a></li>
<li class="toctree-l2"><a class="reference internal" href="docker.html">First Buildbot run with Docker</a></li>
<li class="toctree-l2"><a class="reference internal" href="tour.html">A Quick Tour</a></li>
<li class="toctree-l2 current"><a class="reference internal" href="further.html">Further Reading</a><ul class="current">
<li class="toctree-l3 current"><a class="current reference internal" href="#">Buildbot in 5 minutes - a user-contributed tutorial</a><ul class="simple">
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../manual/index.html">Buildbot Manual</a></li>
<li class="toctree-l1"><a class="reference internal" href="../developer/index.html">Buildbot Development</a></li>
<li class="toctree-l1"><a class="reference internal" href="../relnotes/index.html">Release Notes for Buildbot 0.8.12</a></li>
</ul>

          <div role="search">
            <h3 style="margin-top: 1.5em;">Search</h3>
            <form class="search" action="../search.html" method="get">
                <input type="text" name="q" />
                <input type="submit" value="Go" />
                <input type="hidden" name="check_keywords" value="yes" />
                <input type="hidden" name="area" value="default" />
            </form>
          </div>
        </div>
        <div class="clearer"></div>
      </div>
    </div>

    <div class="footer-wrapper">
      <div class="footer">
        <div class="left">
          <div role="navigation" aria-label="related navigaton">
            <a href="further.html" title="Further Reading"
              >previous</a> |
            <a href="../manual/index.html" title="Buildbot Manual"
              >next</a> |
            <a href="../py-modindex.html" title="Python Module Index"
              >modules</a> |
            <a href="../genindex.html" title="General Index"
              >index</a>
          </div>
          <div role="note" aria-label="source link">
              <br/>
              <a href="../_sources/tutorial/fiveminutes.txt"
                rel="nofollow">Show Source</a>
          </div>
        </div>

        <div class="right">
          
    <div class="footer" role="contentinfo">
        &copy; Copyright Buildbot Team Members.
      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.4.1.
    </div>
        </div>
        <div class="clearer"></div>
      </div>
    </div>

  </body>
</html>