]> git.sur5r.net Git - i3/i3.github.io/blob - docs/4.13/buildbot.html
save docs for 4.13
[i3/i3.github.io] / docs / 4.13 / buildbot.html
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"\r
2     "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\r
3 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">\r
4 <head>\r
5 <link rel="icon" type="image/x-icon" href="/favicon.ico">\r
6 <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />\r
7 <meta name="generator" content="AsciiDoc 8.6.9" />\r
8 <title>i3: The i3 buildbot setup</title>\r
9 <link rel="stylesheet" href="/css/style.css" type="text/css" />\r
10 <link rel="stylesheet" href="/css/xhtml11.css" type="text/css" />\r
11 <script type="text/javascript">\r
12 /*<![CDATA[*/\r
13 document.addEventListener("DOMContentLoaded", function(){asciidoc.footnotes(); asciidoc.toc(2);}, false);\r
14 /*]]>*/\r
15 </script>\r
16 <script type="text/javascript" src="/js/asciidoc-xhtml11.js"></script>\r
17 </head>\r
18 <body class="article">\r
19 \r
20         <div id="main">\r
21             <a href="/"><h1 id="title">i3 - improved tiling WM</h1></a>\r
22                         <ul id="nav">\r
23                                 <li><a style="border-bottom: 2px solid #fff" href="/docs">Docs</a></li>\r
24                                 <li><a href="/screenshots">Screens</a></li>\r
25                                 <li><a href="https://www.reddit.com/r/i3wm/">FAQ</a></li>\r
26                                 <li><a href="/contact">Contact</a></li>\r
27                                 <li><a href="https://github.com/i3/i3/issues">Bugs</a></li>\r
28                         </ul>\r
29         <br style="clear: both">\r
30 <div id="content">\r
31 <div id="header">\r
32 <h1>The i3 buildbot setup</h1>\r
33 <span id="author">Michael Stapelberg</span><br />\r
34 <span id="email"><tt>&lt;<a href="mailto:michael@i3wm.org">michael@i3wm.org</a>&gt;</tt></span><br />\r
35 <span id="revdate">September 2012</span>\r
36 <div id="toc">
37   <div id="toctitle">Table of Contents</div>
38   <noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript>
39 </div>\r
40 </div>\r
41 <div id="preamble">\r
42 <div class="sectionbody">\r
43 <div class="paragraph"><p>This document explains the <a href="http://www.buildbot.net/">buildbot</a> setup we use to\r
44 provide up-to-date documentation and debian packages at <a href="http://build.i3wm.org/">http://build.i3wm.org/</a>.\r
45 We publish these information so that our setup is well-documented (thus\r
46 decreasing future maintenance effort) and because it might be interesting for\r
47 other projects.</p></div>\r
48 </div>\r
49 </div>\r
50 <div class="sect1">\r
51 <h2 id="_introduction">1. Introduction</h2>\r
52 <div class="sectionbody">\r
53 <div class="paragraph"><p>What we are doing in i3 is called Continuous Integration (see\r
54 <a href="http://en.wikipedia.org/wiki/Continuous_integration">http://en.wikipedia.org/wiki/Continuous_integration</a>): we publish the changes we\r
55 make on our local machines as often as possible. In order to maintain a\r
56 continuously high quality, each time any developer pushes changes to the\r
57 official git repository, a number of quality assurance tools start running\r
58 automatically:</p></div>\r
59 <div class="olist arabic"><ol class="arabic">\r
60 <li>\r
61 <p>\r
62 Latest documentation is generated and provided at\r
63    <a href="http://build.i3wm.org/docs/">http://build.i3wm.org/docs/</a>. This makes it easy to link to documentation for\r
64    features which are only in the current git version, not in the released\r
65    version.\r
66 </p>\r
67 </li>\r
68 <li>\r
69 <p>\r
70 The source code is compiled and it is automatically posted to the IRC\r
71    channel whether there were any compiler warnings. While developers should\r
72    notice compiler warnings, this mechanism creates a bit of public pressure\r
73    ("Oh, Michael introduced warnings with this commit!"). More importantly,\r
74    since this mechanism builds a dist tarball and then compiles that tarball,\r
75    any changes to the source which would result in an uncompilable dist tarball\r
76    are immediately obvious. Therefore, we could cut a release from the current\r
77    git version at any point in time.\r
78 </p>\r
79 </li>\r
80 <li>\r
81 <p>\r
82 The clang static analyzer runs and the resulting report is provided at\r
83    <a href="http://build.i3wm.org/clang-analyze/">http://build.i3wm.org/clang-analyze/</a>. While every developer needs to compile\r
84    his code before committing, he doesn’t necessarily use clang (so we catch\r
85    build failures when using clang) and he also probably doesn’t run a static\r
86    analyzer as part of his normal workflow. By just being available without any\r
87    friction, this mechanism encourages developers to look at the report and fix\r
88    problems.\r
89 </p>\r
90 </li>\r
91 <li>\r
92 <p>\r
93 Debian (and Ubuntu) packages are built. This not only ensures that we don’t\r
94    change anything in the source code which would lead to an FTBFS (Fails To\r
95    Build From Source) when building a Debian package, it also goes a long way\r
96    to encourage end users to test i3. To remove the need and resource\r
97    requirements for them to compile their own version of i3 regularly, we\r
98    provide packages that integrate conveniently with a normal Debian system\r
99    (e.g. that are automatically upgraded).\r
100 </p>\r
101 </li>\r
102 </ol></div>\r
103 </div>\r
104 </div>\r
105 <div class="sect1">\r
106 <h2 id="_why_buildbot">2. Why buildbot?</h2>\r
107 <div class="sectionbody">\r
108 <div class="paragraph"><p>Previously, I was unsatisfied with the current state of FOSS CI tools like\r
109 Jenkins, Tinderbox and others. They either seemed bloated, hard to use,\r
110 outdated or unappealing for some other reason.</p></div>\r
111 <div class="paragraph"><p>Then I discovered buildbot and was impressed by its flexibility. It let me\r
112 implement everything I wanted from a CI tool and (in my opinion) it is\r
113 light-weight, easy to deploy and well maintained.</p></div>\r
114 <div class="paragraph"><p>The only downside of buildbot is its configuration and documentation: You need\r
115 to spend quite a bit of time (I needed multiple days) until it works the way\r
116 you want it to and oftentimes, the documentation is far too sparse. This is one\r
117 of the reasons why I’m publishing the i3 setup.</p></div>\r
118 </div>\r
119 </div>\r
120 <div class="sect1">\r
121 <h2 id="_configuration">3. Configuration</h2>\r
122 <div class="sectionbody">\r
123 <div class="paragraph"><p>See the next section for a complete, copy &amp; pasteable configuration file. This\r
124 section covers the most important aspects without covering every line.</p></div>\r
125 <div class="paragraph"><p>This document assumes you are running buildbot 0.8.6p1.</p></div>\r
126 <div class="sect2">\r
127 <h3 id="_change_sources">3.1. Change sources</h3>\r
128 <div class="paragraph"><p>Since i3 uses a central git repository, we use the official buildbot\r
129 <a href="https://github.com/buildbot/buildbot/blob/master/master/contrib/git_buildbot.py">git\r
130 post-receive hook</a> that sends the change information to the buildbot master.</p></div>\r
131 </div>\r
132 <div class="sect2">\r
133 <h3 id="_schedulers">3.2. Schedulers</h3>\r
134 <div class="paragraph"><p>There are two things (called "builders" in buildbot-language) which happen\r
135 whenever a new change in the <tt>next</tt> branch of i3 occurs:</p></div>\r
136 <div class="olist arabic"><ol class="arabic">\r
137 <li>\r
138 <p>\r
139 The "docs" builder builds and uploads the latest documentation. This happens\r
140    directly from the git repository with a custom asciidoc configuration which\r
141    indicates that these docs refer to the git version. Therefore, this builder\r
142    does not benefit from having a dist tarball available (contrary to the other\r
143    builders).\r
144 </p>\r
145 </li>\r
146 <li>\r
147 <p>\r
148 The "dist" builder prepares a dist tarball and then triggers the remaining\r
149    builders. This ensures that building the dist tarball (an operation which\r
150    takes about one minute due to documentation generation) only happens once.\r
151 </p>\r
152 </li>\r
153 </ol></div>\r
154 <div class="paragraph"><p>Here is the relevant configuration part:</p></div>\r
155 <div class="paragraph"><p><strong>Schedulers</strong>:</p></div>\r
156 <div class="listingblock">\r
157 <div class="content">\r
158 <pre><tt>c['schedulers'] = []\r
159 \r
160 c['schedulers'].append(SingleBranchScheduler(\r
161     name = 'dist',\r
162     branch = 'next',\r
163     treeStableTimer = 10,\r
164     builderNames = [ 'dist', 'docs' ],\r
165 ))\r
166 \r
167 c['schedulers'].append(Triggerable(\r
168     name = 'dist-tarball-done',\r
169     builderNames = [ 'compile', 'clang-analyze', 'debian-packages', 'ubuntu-packages' ],\r
170 ))</tt></pre>\r
171 </div></div>\r
172 </div>\r
173 <div class="sect2">\r
174 <h3 id="_building_the_dist_tarball">3.3. Building the dist tarball</h3>\r
175 <div class="paragraph"><p>This builder clones the i3 git repository and runs "make dist", which creates a\r
176 tarball that could be named "i3-4.2.tar.bz2" for example. This tarball is then\r
177 renamed to dist-%(gitversion).tar.bz2 (so that we can work with a predictable\r
178 name in the next steps) and uploaded to the buildbot master (since we can have\r
179 multiple buildslaves, we cannot just let it rest on the buildslave that built\r
180 it). Afterwards, old dist tarballs are cleaned up and the remaining builders\r
181 are triggered:</p></div>\r
182 <div class="paragraph"><p><strong>Building a dist tarball</strong>:</p></div>\r
183 <div class="listingblock">\r
184 <div class="content">\r
185 <pre><tt>factories = {}\r
186 \r
187 f = factories['dist'] = BuildFactory()\r
188 \r
189 # Check out the git repository.\r
190 f.addStep(s_git)\r
191 \r
192 # Fill the 'gitversion' property with the output of git describe --tags.\r
193 f.addStep(shell.SetProperty(command = 'git describe --tags', property = 'gitversion'))\r
194 \r
195 # Build the dist tarball.\r
196 cmd(f, name = 'make dist', command = [ 'make', 'dist' ])\r
197 \r
198 # Rename the created tarball to a well-known name.\r
199 cmd(f,\r
200     name = 'rename tarball',\r
201     command = WithProperties('mv *.tar.bz2 dist-%(gitversion)s.tar.bz2'),\r
202 )\r
203 \r
204 # Upload the dist tarball to the master (other factories download it later).\r
205 f.addStep(transfer.FileUpload(\r
206     slavesrc = WithProperties('dist-%(gitversion)s.tar.bz2'),\r
207     masterdest = WithProperties('distballs/dist-%(gitversion)s.tar.bz2'),\r
208 ))\r
209 \r
210 # Cleanup old dist tarballs (everything older than tree days).\r
211 f.addStep(master.MasterShellCommand(\r
212     command = "find distballs -mtime +3 -exec rm '{}' \;",\r
213     name = 'cleanup old dist tarballs',\r
214 ))\r
215 \r
216 # Everything worked fine, now trigger compilation.\r
217 f.addStep(Trigger(\r
218     schedulerNames = [ 'dist-tarball-done' ],\r
219     copy_properties = [ 'gitversion' ],\r
220 ))</tt></pre>\r
221 </div></div>\r
222 <div class="paragraph"><p>Three things are noteworthy about this part of the configuration:</p></div>\r
223 <div class="olist arabic"><ol class="arabic">\r
224 <li>\r
225 <p>\r
226 For convenience, we call each factory <tt>f</tt> (just like the global buildbot\r
227    config uses <tt>c</tt> for the top-level configuration) and add it to a dictionary.\r
228    Factories in that dictionary are later automatically configured for each\r
229    buildslave.\r
230 </p>\r
231 </li>\r
232 <li>\r
233 <p>\r
234 We have a shared step called <tt>s_git</tt> so that we only have one location in\r
235    the configuration file where we specify the git repository URL and branch.\r
236 </p>\r
237 </li>\r
238 <li>\r
239 <p>\r
240 We have a custom function called <tt>cmd</tt> which is a shortcut for defining a\r
241    <tt>ShellCommand</tt> with <tt>haltOnFailure=True</tt> (since each step is critical) and\r
242    <tt>logEnviron=False</tt> (for brevity).\r
243 </p>\r
244 </li>\r
245 </ol></div>\r
246 <div class="paragraph"><p>Here are their definitions:</p></div>\r
247 <div class="paragraph"><p><strong>cmd</strong>:</p></div>\r
248 <div class="listingblock">\r
249 <div class="content">\r
250 <pre><tt>def cmd(factory, **kwargs):\r
251     factory.addStep(ShellCommand(\r
252         haltOnFailure = True,\r
253         logEnviron = False,\r
254         **kwargs\r
255     ))</tt></pre>\r
256 </div></div>\r
257 <div class="paragraph"><p><strong>s_git</strong>:</p></div>\r
258 <div class="listingblock">\r
259 <div class="content">\r
260 <pre><tt>s_git = Git(\r
261     repourl = 'git://code.i3wm.org/i3',\r
262     branch = 'next',\r
263 \r
264     # Check out the latest revision, not the one which caused this build.\r
265     alwaysUseLatest = True,\r
266 \r
267     # We cannot use shallow because it breaks git describe --tags.\r
268     shallow = False,\r
269 \r
270     # Delete remnants of previous builds.\r
271     mode = 'full',\r
272 \r
273     # Store checkouts in source/ and copy them over to build/ to save\r
274     # bandwidth.\r
275     method = 'copy',\r
276 )</tt></pre>\r
277 </div></div>\r
278 </div>\r
279 <div class="sect2">\r
280 <h3 id="_compiling_the_dist_tarball">3.4. Compiling the dist tarball</h3>\r
281 <div class="paragraph"><p>For this builder to work, you obviously need to install all the\r
282 build-dependencies for your software on each buildslave. In the case of i3,\r
283 this can be done with <tt>apt-get build-dep i3-wm</tt>.</p></div>\r
284 <div class="paragraph"><p>The compilation is pretty straight-forward since it uses the builtin <tt>Compile</tt>\r
285 step. We call <tt>make</tt> with <tt>-j4</tt> (we don’t have enough buildslaves to make\r
286 figuring out the amount of cores at build-time worthwhile) and <tt>DEBUG=0</tt> to\r
287 simulate release build conditions. Also, we pass the preprocessor flag\r
288 <tt>-D_FORTIFY_SOURCE=2</tt> and the compiler flags <tt>-Wformat</tt> and <tt>-Wformat-security</tt>\r
289 to enable additional warnings.</p></div>\r
290 <div class="paragraph"><p><strong>Compiling the dist tarball</strong>:</p></div>\r
291 <div class="listingblock">\r
292 <div class="content">\r
293 <pre><tt>f = factories['compile'] = BuildFactory()\r
294 unpack_dist_tarball(f)\r
295 f.addStep(Compile(\r
296     command = [ 'make', 'DEBUG=0', '-j4' ],\r
297     warningPattern = '.*warning: ',\r
298     warnOnWarnings = True,\r
299     workdir = 'build/DIST',\r
300     env = {\r
301       'CPPFLAGS': '-D_FORTIFY_SOURCE=2',\r
302       'CFLAGS': '-Wformat -Wformat-security'\r
303     },\r
304 ))\r
305 \r
306 f.addStep(WarningsToIRC())</tt></pre>\r
307 </div></div>\r
308 <div class="paragraph"><p>Again, we use custom functions (and a custom buildstep) to make our lives\r
309 easier. Here is the definition of unpack_dist_tarball which adds three steps to\r
310 the factory that download and unpack the dist tarball to the <tt>DIST/</tt> directory:</p></div>\r
311 <div class="paragraph"><p><strong>unpack_dist_tarball</strong>:</p></div>\r
312 <div class="listingblock">\r
313 <div class="content">\r
314 <pre><tt>def unpack_dist_tarball(factory):\r
315     factory.addStep(transfer.FileDownload(\r
316         mastersrc = WithProperties('distballs/dist-%(gitversion)s.tar.bz2'),\r
317         slavedest = 'dist.tar.bz2',\r
318     ))\r
319 \r
320     factory.addStep(slave.MakeDirectory(dir = 'build/DIST'))\r
321 \r
322     cmd(factory,\r
323         name = 'unpack dist tarball',\r
324         command = [ 'tar', 'xf', 'dist.tar.bz2', '-C', 'DIST', '--strip-components=1' ],\r
325     )</tt></pre>\r
326 </div></div>\r
327 <div class="paragraph"><p>The <tt>WarningsToIRC</tt> build step is a custom build step which sets a property\r
328 called "ircsuffix" that is used by our custom IRC bot. This is covered later in\r
329 more detail. This property gets set to a green or red message, depending on\r
330 whether there were any warnings:</p></div>\r
331 <div class="paragraph"><p><strong>WarningsToIRC</strong>:</p></div>\r
332 <div class="listingblock">\r
333 <div class="content">\r
334 <pre><tt>class WarningsToIRC(buildstep.BuildStep):\r
335     def start(self):\r
336         warnings = self.getProperty("warnings-count")\r
337         if warnings is not None and int(warnings) &gt; 0:\r
338             warnings = int(warnings)  # just to be sure\r
339             self.setProperty("ircsuffix", ("\0037 with %d warning%s!" %\r
340                 (warnings, "s" if warnings != 1 else "")))\r
341         else:\r
342             self.setProperty("ircsuffix", "\0033 without warnings")\r
343         self.finished(SUCCESS)</tt></pre>\r
344 </div></div>\r
345 </div>\r
346 <div class="sect2">\r
347 <h3 id="_static_code_analysis">3.5. Static code analysis</h3>\r
348 <div class="paragraph"><p>For this builder to work, you additionally need the <tt>clang</tt> compiler on each\r
349 buildslave: <tt>apt-get install clang</tt>.</p></div>\r
350 <div class="paragraph"><p>This builder uses only custom functions which you already know by now. It runs\r
351 scan-build, then moves scan-build’s output from a date-based directory directly\r
352 into the <tt>CLANG/</tt> directory and uploads that to the buildmaster.</p></div>\r
353 <div class="paragraph"><p>On the buildmaster, a webserver is configured which has a symlink to\r
354 <tt>/home/build/i3-master/htdocs/clang-analyze</tt> in its document root.</p></div>\r
355 <div class="paragraph"><p><strong>static code analysis</strong>:</p></div>\r
356 <div class="listingblock">\r
357 <div class="content">\r
358 <pre><tt>f = factories['clang-analyze'] = BuildFactory()\r
359 unpack_dist_tarball(f)\r
360 cmd(f,\r
361     name='analyze',\r
362     command = [\r
363         'scan-build',\r
364         '-o', '../CLANG',\r
365         '--html-title', WithProperties('Analysis of i3 v%(gitversion)s'),\r
366         'make', '-j8',\r
367     ],\r
368     workdir = 'build/DIST',\r
369 )\r
370 \r
371 # remove the subdirectory -- we always want to overwrite\r
372 cmd(f, command = 'mv CLANG/*/* CLANG/')\r
373 \r
374 f.addStep(transfer.DirectoryUpload(\r
375     slavesrc = 'CLANG',\r
376     masterdest = 'htdocs/clang-analyze',\r
377     compress = 'bz2',\r
378     name = 'upload output',\r
379 ))\r
380 \r
381 f.addStep(ClangToIRC())</tt></pre>\r
382 </div></div>\r
383 <div class="paragraph"><p>The <tt>ClangToIRC</tt> custom step is even simpler than <tt>WarningsToIRC</tt>. It simply\r
384 sets the ircsuffix property to a static message:</p></div>\r
385 <div class="paragraph"><p><strong>ClangToIRC</strong>:</p></div>\r
386 <div class="listingblock">\r
387 <div class="content">\r
388 <pre><tt>class ClangToIRC(buildstep.BuildStep):\r
389     def start(self):\r
390         self.setProperty("ircsuffix", ", see http://build.i3wm.org/clang-analyze/")\r
391         self.finished(SUCCESS)</tt></pre>\r
392 </div></div>\r
393 </div>\r
394 <div class="sect2">\r
395 <h3 id="_generating_documentation">3.6. Generating documentation</h3>\r
396 <div class="paragraph"><p>This builder is the one which is the least clean of all. It uses the Debian\r
397 packaging information to decide which docs to publish and which manpages to\r
398 generate. Additionally, it uses a for loop instead of calling a script. I\r
399 recommend including a script to do this in your repository instead.</p></div>\r
400 <div class="paragraph"><p>Apart from these concerns, the builder is straight-forward: It clones the git\r
401 repository, generates the documentation and then uploads the documentation to\r
402 the buildmaster:</p></div>\r
403 <div class="paragraph"><p><strong>Generating documentation</strong>:</p></div>\r
404 <div class="listingblock">\r
405 <div class="content">\r
406 <pre><tt>f = factories['docs'] = BuildFactory()\r
407 f.addStep(s_git)\r
408 # Fill the 'gitversion' property with the output of git describe --tags.\r
409 f.addStep(shell.SetProperty(command = 'git describe --tags', property = 'gitversion'))\r
410 cmd(f, name = 'build docs', command = [ 'make', '-C', 'docs', "ASCIIDOC=asciidoc -a linkcss -a stylesdir=http://i3wm.org/css -a scriptsdir=http://i3wm.org/js --backend=xhtml11 -f docs/asciidoc-git.conf" ])\r
411 cmd(f, name = 'build manpages', command = "for file in $(sed 's/\.1$/.man/g' debian/i3-wm.manpages); do asciidoc -a linkcss -a stylesdir=http://i3wm.org/css -a scriptsdir=http://i3wm.org/js --backend=xhtml11 -f docs/asciidoc-git.conf \"$file\"; done")\r
412 f.addStep(slave.MakeDirectory(dir='build/COPY-DOCS'))\r
413 cmd(f, name = 'copy docs', command = "cp $(tr '\\n' ' ' &lt; debian/i3-wm.docs) COPY-DOCS")\r
414 cmd(f, name = 'copy manpages', command = "cp $(sed 's/\.1$/.html/g' debian/i3-wm.manpages | tr '\\n' ' ') COPY-DOCS")\r
415 \r
416 f.addStep(transfer.DirectoryUpload(\r
417     slavesrc = 'COPY-DOCS',\r
418     masterdest = 'htdocs/docs-git',\r
419     compress = 'bz2',\r
420     name = 'upload docs'))\r
421 \r
422 f.addStep(DocsToIRC())</tt></pre>\r
423 </div></div>\r
424 <div class="paragraph"><p>Just as <tt>ClangToIRC</tt>, <tt>DocsToIRC</tt> appends a static message:</p></div>\r
425 <div class="paragraph"><p><strong>DocsToIRC</strong>:</p></div>\r
426 <div class="listingblock">\r
427 <div class="content">\r
428 <pre><tt>class DocsToIRC(buildstep.BuildStep):\r
429     def start(self):\r
430         self.setProperty("ircsuffix", ", see http://build.i3wm.org/docs/")\r
431         self.finished(SUCCESS)</tt></pre>\r
432 </div></div>\r
433 </div>\r
434 <div class="sect2">\r
435 <h3 id="_building_debian_ubuntu_packages">3.7. Building Debian/Ubuntu packages</h3>\r
436 <div class="paragraph"><p>This is the most complex builder of all. It uses <tt>pbuilder-dist</tt>, <tt>debchange</tt>,\r
437 <tt>dpkg-buildpackage</tt> and <tt>reprepro</tt> to generate a Debian repository with a\r
438 cleanly compiled package for amd64 and i386. In order for it to work, you need\r
439 to install the following packages: <tt>apt-get install devscripts dpkg-dev\r
440 reprepro ubuntu-dev-tools pbuilder</tt>. Afterwards, you need to allow the user as\r
441 which the buildslave runs to execute pbuilder via sudo without needing a\r
442 password, so add a config file like this one:</p></div>\r
443 <div class="paragraph"><p><strong>sudoers.d</strong>:</p></div>\r
444 <div class="listingblock">\r
445 <div class="content">\r
446 <pre><tt>echo 'build    ALL= NOPASSWD: SETENV: /usr/sbin/pbuilder' &gt; /etc/sudoers.d/build</tt></pre>\r
447 </div></div>\r
448 <div class="paragraph"><p>Then, as the user as which your buildslave runs, setup the pbuilder\r
449 environments (you only need to do this once):</p></div>\r
450 <div class="paragraph"><p><strong>pbuilder preparation</strong>:</p></div>\r
451 <div class="listingblock">\r
452 <div class="content">\r
453 <pre><tt>sudo ln -s pbuilder-dist /usr/bin/pbuilder-sid-amd64\r
454 sudo ln -s pbuilder-dist /usr/bin/pbuilder-sid-i386\r
455 pbuilder-sid-amd64 create\r
456 pbuilder-sid-i386 create</tt></pre>\r
457 </div></div>\r
458 <div class="paragraph"><p>Also, you will need a GPG key to sign these packages.</p></div>\r
459 <div class="paragraph"><p>The debian builder starts by unpacking the dist tarball, copying the Debian\r
460 packaging from git, creating an empty Debian repository with the\r
461 <tt>i3-autobuild-keyring</tt> contents in it. It then adds a new changelog entry to\r
462 reflect the git version and the fact that this package was built automatically,\r
463 builds a source package with <tt>dpkg-buildpackage</tt> and adds it to the repository.\r
464 Afterwards, it updates each pbuilder and builds binary packages for each\r
465 architecture (amd64 and i386). After adding the resulting packages to the\r
466 repository, it uploads the repository to the buildmaster:</p></div>\r
467 <div class="paragraph"><p><strong>Debian builder</strong>:</p></div>\r
468 <div class="listingblock">\r
469 <div class="content">\r
470 <pre><tt>distributions = [ 'sid-amd64', 'sid-i386' ]\r
471 gpg_key = 'BE1DB1F1'\r
472 \r
473 f = factories['debian-packages'] = BuildFactory()\r
474 # We need the git repository for the Debian packaging.\r
475 f.addStep(s_git)\r
476 unpack_dist_tarball(f)\r
477 cmd(f, name = 'copy packaging', command = "cp -r debian DIST/")\r
478 \r
479 # Add a new changelog entry to have the git version in the package version.\r
480 cmd(f,\r
481     name = 'update changelog',\r
482     workdir = 'build/DIST',\r
483     command = [ 'debchange', '-m', '-l', WithProperties('+g%(gitversion)s'), 'Automatically built' ],\r
484 )\r
485 \r
486 cmd(f,\r
487     name = 'source pkg',\r
488     command = [ 'dpkg-buildpackage', '-S', '-us', '-uc' ],\r
489     workdir = 'build/DIST',\r
490 )\r
491 \r
492 for dist in distributions:\r
493     f.addStep(slave.MakeDirectory(dir = 'build/RESULT-' + dist))\r
494 \r
495 # Create debian sid repository\r
496 f.addStep(slave.MakeDirectory(dir = 'build/REPO-sid/conf'))\r
497 f.addStep(transfer.StringDownload(\r
498     """Codename: sid\r
499 Suite: unstable\r
500 Architectures: i386 amd64 source\r
501 Components: main\r
502 DebIndices: Packages Release . .gz .bz2\r
503 DscIndices: Sources Release . .gz .bz2\r
504 SignWith: %(gpg_key)s\r
505 """ % { "gpg_key": gpg_key },\r
506     slavedest = 'REPO-sid/conf/distributions',\r
507 ))\r
508 \r
509 # add source package to repository\r
510 reprepro_include(f, 'i3-wm*_source.changes', 'dsc')\r
511 \r
512 # Add keyring to the repository. We need to run git clone on our own because\r
513 # the Git() step assumes there’s precisely one repository we want to deal with.\r
514 # No big deal since the i3-autobuild-keyring repository is not big.\r
515 cmd(f,\r
516     name = 'clone keyring repo',\r
517     command = 'git clone git://code.i3wm.org/i3-autobuild-keyring',\r
518 )\r
519 reprepro_include(f, 'i3-autobuild-keyring/prebuilt/*.changes')\r
520 \r
521 for dist in distributions:\r
522     # update the pbuilder\r
523     cmd(f, name = 'update builder', command = 'pbuilder-' + dist + ' update')\r
524 \r
525     # build the package for each dist\r
526     f.addStep(ShellCommand(\r
527         logEnviron = False,\r
528         name = 'pkg ' + dist,\r
529         command = 'pbuilder-' + dist + ' build --binary-arch \\r
530 --buildresult RESULT-' + dist + ' --debbuildopts -j8 i3-wm*dsc',\r
531         warnOnFailure = True\r
532     ))\r
533 \r
534     reprepro_include(f, 'RESULT-' + dist + '/*.changes')\r
535 \r
536 # upload the sid repo\r
537 # Since the next step is cleaning up old files, we set haltOnFailure=True -- we\r
538 # prefer providing old packages over providing no packages at all :).\r
539 for directory in [ 'pool', 'dists' ]:\r
540     f.addStep(transfer.DirectoryUpload(\r
541         slavesrc = 'REPO-sid/' + directory,\r
542         masterdest = 'htdocs/debian/sid/' + directory,\r
543         compress = 'bz2',\r
544         name = 'upload sid ' + directory,\r
545         haltOnFailure = True,\r
546     ))\r
547 \r
548 f.addStep(master.MasterShellCommand(\r
549     command = "find htdocs/debian/sid/pool -mtime +3 -exec rm '{}' \;",\r
550     name = 'cleanup old packages',\r
551 ))\r
552 \r
553 # We ensure there is an empty i18n/Index to speed up apt (so that it does not\r
554 # try to download Translation-*)\r
555 f.addStep(master.MasterShellCommand(\r
556     command = [ 'mkdir', '-p', 'htdocs/debian/sid/dists/sid/main/i18n' ],\r
557     name = 'create i18n folder',\r
558 ))\r
559 f.addStep(master.MasterShellCommand(\r
560     command = [ 'touch', 'htdocs/debian/sid/dists/sid/main/i18n/Index' ],\r
561     name = 'touch i18n/Index',\r
562 ))</tt></pre>\r
563 </div></div>\r
564 <div class="paragraph"><p>The <tt>reprepro_include</tt> command is defined as follows:</p></div>\r
565 <div class="paragraph"><p><strong>reprepro_include</strong>:</p></div>\r
566 <div class="listingblock">\r
567 <div class="content">\r
568 <pre><tt>def reprepro_include(factory, path, debtype='deb', **kwargs):\r
569     cmd(factory,\r
570         name = 'reprepro include',\r
571         command = 'reprepro --ignore=wrongdistribution -T ' + debtype + ' -b REPO-sid include sid ' + path,\r
572         **kwargs\r
573     )</tt></pre>\r
574 </div></div>\r
575 <div class="paragraph"><p>Running such a builder for Ubuntu works exactly the same way, but you need to\r
576 replace "sid" with "precise" in all places (see the full configuration file for\r
577 an example).</p></div>\r
578 </div>\r
579 <div class="sect2">\r
580 <h3 id="_status_targets">3.8. Status targets</h3>\r
581 <div class="paragraph"><p>We don’t advertise the HTTP status target. Instead, status is posted to IRC via\r
582 a custom bot. This bot provides an HTTP end point and buildbot is configured to\r
583 push status changes to that endpoint:</p></div>\r
584 <div class="paragraph"><p><strong>http status target</strong>:</p></div>\r
585 <div class="listingblock">\r
586 <div class="content">\r
587 <pre><tt>c['status'].append(buildbot.status.status_push.HttpStatusPush(\r
588     serverUrl = 'http://localhost:8080/push_buildbot',\r
589 ))</tt></pre>\r
590 </div></div>\r
591 <div class="paragraph"><p>You can find the source code of that bot at\r
592 <a href="http://code.stapelberg.de/git/go-buildbot-announce/">http://code.stapelberg.de/git/go-buildbot-announce/</a>. As the name suggests, it\r
593 is written in Go. Also, it is quite specific to i3, so you might be better off\r
594 implementing such a bot (or plugin) on your own. It might make for a nice\r
595 example, though, especially back when its only feature was announcing the build\r
596 status:</p></div>\r
597 <div class="paragraph"><p><a href="http://code.stapelberg.de/git/go-buildbot-announce/tree/src/i3build.go?id=eeebf1a546454c8a0d82ca623886bb835cd32ba0">http://code.stapelberg.de/git/go-buildbot-announce/tree/src/i3build.go?id=eeebf1a546454c8a0d82ca623886bb835cd32ba0</a></p></div>\r
598 </div>\r
599 <div class="sect2">\r
600 <h3 id="_creating_the_buildslave">3.9. Creating the buildslave</h3>\r
601 <div class="paragraph"><p>One more thing to note is that when creating the buildslave, you should use the\r
602 <tt>--umask</tt> argument to configure the umask for all generated files:</p></div>\r
603 <div class="paragraph"><p><strong>Creating the buildslave</strong>:</p></div>\r
604 <div class="listingblock">\r
605 <div class="content">\r
606 <pre><tt>buildslave create-slave --umask=022 i3-buildslave buildbot.i3wm.org build-1 &lt;password&gt;</tt></pre>\r
607 </div></div>\r
608 </div>\r
609 </div>\r
610 </div>\r
611 <div class="sect1">\r
612 <h2 id="_full_configuration_file">4. Full configuration file</h2>\r
613 <div class="sectionbody">\r
614 <div class="paragraph"><p>This is the full configuration file, as tested and currently in use (except for\r
615 the passwords, though):</p></div>\r
616 <div class="paragraph"><p><strong>master.cfg</strong>:</p></div>\r
617 <div class="listingblock">\r
618 <div class="content">\r
619 <pre><tt># -*- python -*-\r
620 # -*- coding: utf-8\r
621 # vim:ts=4:sw=4:expandtab:syntax=python\r
622 #\r
623 # i3 buildbot configuration\r
624 # © 2012 Michael Stapelberg, Public Domain\r
625 # see http://i3wm.org/docs/buildbot.html for more information.\r
626 \r
627 from buildbot.buildslave import BuildSlave\r
628 from buildbot.changes import pb\r
629 from buildbot.schedulers.basic import SingleBranchScheduler\r
630 from buildbot.schedulers.triggerable import Triggerable\r
631 from buildbot.process.properties import WithProperties\r
632 from buildbot.process.factory import BuildFactory\r
633 from buildbot.steps.source.git import Git\r
634 from buildbot.steps.shell import ShellCommand\r
635 from buildbot.steps.shell import Compile\r
636 from buildbot.steps.trigger import Trigger\r
637 from buildbot.steps import shell, transfer, master, slave\r
638 from buildbot.config import BuilderConfig\r
639 from buildbot.process import buildstep\r
640 from buildbot.status import html\r
641 from buildbot.status import words\r
642 import buildbot.status.status_push\r
643 from buildbot.status.web import auth, authz\r
644 from buildbot.status.builder import SUCCESS, FAILURE\r
645 \r
646 c = BuildmasterConfig = {}\r
647 \r
648 c['slaves'] = [BuildSlave('docsteel-vm', 'secret')]\r
649 c['slavePortnum'] = 9989\r
650 # Changes are pushed to buildbot using a git hook.\r
651 c['change_source'] = [pb.PBChangeSource(\r
652     user = 'i3-source',\r
653     passwd = 'secret',\r
654 )]\r
655 \r
656 ################################################################################\r
657 # schedulers\r
658 ################################################################################\r
659 \r
660 c['schedulers'] = []\r
661 \r
662 # The first scheduler kicks off multiple builders:\r
663 # • 'dist' builds a dist tarball and starts the triggerable schedulers\r
664 #   'compile'\r
665 # • 'docs' builds the documentation with a special asciidoc configuration\r
666 #   (therefore, it does not profit from a dist tarball and can be run in\r
667 #    parallel).\r
668 c['schedulers'].append(SingleBranchScheduler(\r
669     name = 'dist',\r
670     branch = 'next',\r
671     treeStableTimer = 10,\r
672     builderNames = [ 'dist', 'docs' ],\r
673 ))\r
674 \r
675 c['schedulers'].append(Triggerable(\r
676     name = 'dist-tarball-done',\r
677     builderNames = [ 'compile', 'clang-analyze', 'debian-packages', 'ubuntu-packages' ],\r
678 ))\r
679 \r
680 ################################################################################\r
681 # Shortcuts for builders\r
682 ################################################################################\r
683 \r
684 # shortcut for a ShellCommand with haltOnFailure=True, logEnviron=False\r
685 def cmd(factory, **kwargs):\r
686     factory.addStep(ShellCommand(\r
687         haltOnFailure=True,\r
688         logEnviron=False,\r
689         **kwargs\r
690     ))\r
691 \r
692 # Shortcut to add steps necessary to download and unpack the dist tarball.\r
693 def unpack_dist_tarball(factory):\r
694     factory.addStep(transfer.FileDownload(\r
695         mastersrc=WithProperties('distballs/dist-%(gitversion)s.tar.bz2'),\r
696         slavedest='dist.tar.bz2',\r
697     ))\r
698     factory.addStep(slave.MakeDirectory(dir='build/DIST'))\r
699     cmd(factory,\r
700         name = 'unpack dist tarball',\r
701         command = [ 'tar', 'xf', 'dist.tar.bz2', '-C', 'DIST', '--strip-components=1' ],\r
702     )\r
703 \r
704 # Includes the given path in REPO-sid using reprepro.\r
705 def reprepro_include(factory, path, debtype='deb', **kwargs):\r
706     cmd(factory,\r
707         name = 'reprepro include',\r
708         command = 'reprepro --ignore=wrongdistribution -T ' + debtype + ' -b REPO-sid include sid ' + path,\r
709         **kwargs\r
710     )\r
711 \r
712 def reprepro_include_ubuntu(factory, path, debtype='deb', **kwargs):\r
713     cmd(factory,\r
714         name = 'reprepro include',\r
715         command = 'reprepro --ignore=wrongdistribution -T ' + debtype + ' -b REPO-sid include precise ' + path,\r
716         **kwargs\r
717     )\r
718 \r
719 ################################################################################\r
720 # Custom steps\r
721 ################################################################################\r
722 \r
723 # Adds the ircsuffix property to reflect whether there were warnings.\r
724 class WarningsToIRC(buildstep.BuildStep):\r
725   def start(self):\r
726     warnings = self.getProperty("warnings-count")\r
727     if warnings is not None and int(warnings) &gt; 0:\r
728       warnings = int(warnings)  # just to be sure\r
729       self.setProperty("ircsuffix", "\0037 with %d warning%s!" % (warnings, "s" if warnings != 1 else ""))\r
730     else:\r
731       self.setProperty("ircsuffix", "\0033 without warnings")\r
732     self.finished(SUCCESS)\r
733 \r
734 # Adds a link to the automatically generated documentation.\r
735 class DocsToIRC(buildstep.BuildStep):\r
736   def start(self):\r
737     self.setProperty("ircsuffix", ", see http://build.i3wm.org/docs/")\r
738     self.finished(SUCCESS)\r
739 \r
740 # Adds a link to the clang report.\r
741 class ClangToIRC(buildstep.BuildStep):\r
742   def start(self):\r
743     self.setProperty("ircsuffix", ", see http://build.i3wm.org/clang-analyze/")\r
744     self.finished(SUCCESS)\r
745 \r
746 ################################################################################\r
747 # Shared steps, used in different factories.\r
748 ################################################################################\r
749 \r
750 s_git = Git(\r
751     repourl='git://code.i3wm.org/i3',\r
752     branch='next',\r
753 \r
754     # Check out the latest revision, not the one which caused this build.\r
755     alwaysUseLatest=True,\r
756 \r
757     # We cannot use shallow because it breaks git describe --tags.\r
758     shallow=False,\r
759 \r
760     # Delete remnants of previous builds.\r
761     mode='full',\r
762 \r
763     # Store checkouts in source/ and copy them over to build/ to save\r
764     # bandwidth.\r
765     method='copy',\r
766 \r
767     # XXX: In newer versions of buildbot (&gt; 0.8.6), we want to use\r
768     # getDescription={ 'tags': True } here and get rid of the extra git\r
769     # describe --tags step.\r
770 )\r
771 \r
772 ################################################################################\r
773 # factory: "dist" — builds the dist tarball once (used by all other factories)\r
774 ################################################################################\r
775 \r
776 factories = {}\r
777 \r
778 f = factories['dist'] = BuildFactory()\r
779 # Check out the git repository.\r
780 f.addStep(s_git)\r
781 # Fill the 'gitversion' property with the output of git describe --tags.\r
782 f.addStep(shell.SetProperty(command = 'git describe --tags', property = 'gitversion'))\r
783 # Build the dist tarball.\r
784 cmd(f, name = 'make dist', command = [ 'make', 'dist' ])\r
785 # Rename the created tarball to a well-known name.\r
786 cmd(f, name = 'rename tarball', command = WithProperties('mv *.tar.bz2 dist-%(gitversion)s.tar.bz2'))\r
787 # Upload the dist tarball to the master (other factories download it later).\r
788 f.addStep(transfer.FileUpload(\r
789     slavesrc = WithProperties('dist-%(gitversion)s.tar.bz2'),\r
790     masterdest = WithProperties('distballs/dist-%(gitversion)s.tar.bz2'),\r
791 ))\r
792 # Cleanup old dist tarballs (everything older than tree days).\r
793 f.addStep(master.MasterShellCommand(\r
794     command = "find distballs -mtime +3 -exec rm '{}' \;",\r
795     name = 'cleanup old dist tarballs',\r
796 ))\r
797 # Everything worked fine, now trigger compilation.\r
798 f.addStep(Trigger(\r
799     schedulerNames = [ 'dist-tarball-done' ],\r
800     copy_properties = [ 'gitversion' ],\r
801 ))\r
802 \r
803 ################################################################################\r
804 # factory: "compile" — compiles the dist tarball and reports warnings\r
805 ################################################################################\r
806 \r
807 f = factories['compile'] = BuildFactory()\r
808 unpack_dist_tarball(f)\r
809 f.addStep(Compile(\r
810     command = [ 'make', 'DEBUG=0', '-j4' ],\r
811     warningPattern = '.*warning: ',\r
812     warnOnWarnings = True,\r
813     workdir = 'build/DIST',\r
814     env = {\r
815       'CPPFLAGS': '-D_FORTIFY_SOURCE=2',\r
816       'CFLAGS': '-Wformat -Wformat-security'\r
817     },\r
818 ))\r
819 \r
820 f.addStep(WarningsToIRC())\r
821 \r
822 ################################################################################\r
823 # factory: "clang-analyze" — runs a static code analysis\r
824 ################################################################################\r
825 # $ sudo apt-get install clang\r
826 \r
827 f = factories['clang-analyze'] = BuildFactory()\r
828 unpack_dist_tarball(f)\r
829 cmd(f,\r
830     name='analyze',\r
831     command = [\r
832         'scan-build',\r
833         '-o', '../CLANG',\r
834         '--html-title', WithProperties('Analysis of i3 v%(gitversion)s'),\r
835         'make', '-j8',\r
836     ],\r
837     workdir = 'build/DIST',\r
838 )\r
839 \r
840 # remove the subdirectory -- we always want to overwrite\r
841 cmd(f, command = 'mv CLANG/*/* CLANG/')\r
842 \r
843 f.addStep(transfer.DirectoryUpload(\r
844     slavesrc = 'CLANG',\r
845     masterdest = 'htdocs/clang-analyze',\r
846     compress = 'bz2',\r
847     name = 'upload output',\r
848 ))\r
849 \r
850 f.addStep(ClangToIRC())\r
851 \r
852 ################################################################################\r
853 # factory: "docs" — builds documentation with a special asciidoc conf\r
854 ################################################################################\r
855 \r
856 f = factories['docs'] = BuildFactory()\r
857 f.addStep(s_git)\r
858 # Fill the 'gitversion' property with the output of git describe --tags.\r
859 f.addStep(shell.SetProperty(command = 'git describe --tags', property = 'gitversion'))\r
860 cmd(f, name = 'build docs', command = [ 'make', '-C', 'docs', "ASCIIDOC=asciidoc -a linkcss -a stylesdir=http://i3wm.org/css -a scriptsdir=http://i3wm.org/js --backend=xhtml11 -f docs/asciidoc-git.conf" ])\r
861 cmd(f, name = 'build manpages', command = "for file in $(sed 's/\.1$/.man/g' debian/i3-wm.manpages); do asciidoc -a linkcss -a stylesdir=http://i3wm.org/css -a scriptsdir=http://i3wm.org/js --backend=xhtml11 -f docs/asciidoc-git.conf \"$file\"; done")\r
862 f.addStep(slave.MakeDirectory(dir='build/COPY-DOCS'))\r
863 cmd(f, name = 'copy docs', command = "cp $(tr '\\n' ' ' &lt; debian/i3-wm.docs) COPY-DOCS")\r
864 cmd(f, name = 'copy manpages', command = "cp $(sed 's/\.1$/.html/g' debian/i3-wm.manpages | tr '\\n' ' ') COPY-DOCS")\r
865 \r
866 f.addStep(transfer.DirectoryUpload(\r
867     slavesrc = 'COPY-DOCS',\r
868     masterdest = 'htdocs/docs-git',\r
869     compress = 'bz2',\r
870     name = 'upload docs'))\r
871 \r
872 f.addStep(DocsToIRC())\r
873 \r
874 ################################################################################\r
875 # factory: "debian-packages" — builds Debian (sid) packages for amd64 and i386\r
876 ################################################################################\r
877 \r
878 distributions = [ 'sid-amd64', 'sid-i386' ]\r
879 gpg_key = 'BE1DB1F1'\r
880 \r
881 f = factories['debian-packages'] = BuildFactory()\r
882 # We need the git repository for the Debian packaging.\r
883 f.addStep(s_git)\r
884 unpack_dist_tarball(f)\r
885 cmd(f, name='copy packaging', command = "cp -r debian DIST/")\r
886 \r
887 # Add a new changelog entry to have the git version in the package version.\r
888 cmd(f,\r
889     name = 'update changelog',\r
890     workdir = 'build/DIST',\r
891     command = [ 'debchange', '-m', '-l', WithProperties('+g%(gitversion)s'), 'Automatically built' ],\r
892 )\r
893 \r
894 cmd(f,\r
895     name = 'source pkg',\r
896     command = [ 'dpkg-buildpackage', '-S', '-us', '-uc' ],\r
897     workdir = 'build/DIST',\r
898 )\r
899 \r
900 for dist in distributions:\r
901     f.addStep(slave.MakeDirectory(dir='build/RESULT-' + dist))\r
902 \r
903 # Create debian sid repository\r
904 f.addStep(slave.MakeDirectory(dir='build/REPO-sid/conf'))\r
905 f.addStep(transfer.StringDownload(\r
906     """Codename: sid\r
907 Suite: unstable\r
908 Architectures: i386 amd64 source\r
909 Components: main\r
910 DebIndices: Packages Release . .gz .bz2\r
911 DscIndices: Sources Release . .gz .bz2\r
912 SignWith: %(gpg_key)s\r
913 """ % { "gpg_key": gpg_key },\r
914     slavedest = 'REPO-sid/conf/distributions',\r
915 ))\r
916 \r
917 # add source package to repository\r
918 reprepro_include(f, 'i3-wm*_source.changes', 'dsc')\r
919 \r
920 # Add keyring to the repository. We need to run git clone on our own because\r
921 # the Git() step assumes there’s precisely one repository we want to deal with.\r
922 # No big deal since the i3-autobuild-keyring repository is not big.\r
923 cmd(f, name='clone keyring repo', command = 'git clone git://code.i3wm.org/i3-autobuild-keyring')\r
924 reprepro_include(f, 'i3-autobuild-keyring/prebuilt/*.changes')\r
925 \r
926 for dist in distributions:\r
927     # update the pbuilder\r
928     cmd(f, name = 'update builder', command = 'pbuilder-' + dist + ' update')\r
929 \r
930     # build the package for each dist\r
931     f.addStep(ShellCommand(\r
932         logEnviron = False,\r
933         name = 'pkg ' + dist,\r
934         command = 'pbuilder-' + dist + ' build --binary-arch \\r
935 --buildresult RESULT-' + dist + ' --debbuildopts -j8 i3-wm*dsc',\r
936         warnOnFailure = True\r
937     ))\r
938 \r
939     reprepro_include(f, 'RESULT-' + dist + '/*.changes')\r
940 \r
941 # upload the sid repo\r
942 # Since the next step is cleaning up old files, we set haltOnFailure=True -- we\r
943 # prefer providing old packages over providing no packages at all :).\r
944 for directory in [ 'pool', 'dists' ]:\r
945     f.addStep(transfer.DirectoryUpload(\r
946         slavesrc = 'REPO-sid/' + directory,\r
947         masterdest = 'htdocs/debian/sid/' + directory,\r
948         compress = 'bz2',\r
949         name = 'upload sid ' + directory,\r
950         haltOnFailure = True,\r
951     ))\r
952 \r
953 f.addStep(master.MasterShellCommand(\r
954     command = "find htdocs/debian/sid/pool -mtime +3 -exec rm '{}' \;",\r
955     name = 'cleanup old packages',\r
956 ))\r
957 \r
958 # We ensure there is an empty i18n/Index to speed up apt (so that it does not\r
959 # try to download Translation-*)\r
960 f.addStep(master.MasterShellCommand(\r
961     command = [ 'mkdir', '-p', 'htdocs/debian/sid/dists/sid/main/i18n' ],\r
962     name = 'create i18n folder',\r
963 ))\r
964 f.addStep(master.MasterShellCommand(\r
965     command = [ 'touch', 'htdocs/debian/sid/dists/sid/main/i18n/Index' ],\r
966     name = 'touch i18n/Index',\r
967 ))\r
968 \r
969 ################################################################################\r
970 # factory: "ubuntu-packages" — builds Ubuntu (precise) packages for amd64 and i386\r
971 ################################################################################\r
972 \r
973 distributions = [ 'precise-amd64', 'precise-i386' ]\r
974 gpg_key = 'BE1DB1F1'\r
975 \r
976 f = factories['ubuntu-packages'] = BuildFactory()\r
977 # We need the git repository for the Debian packaging.\r
978 f.addStep(s_git)\r
979 unpack_dist_tarball(f)\r
980 cmd(f, name='copy packaging', command = "cp -r debian DIST/")\r
981 \r
982 # Add a new changelog entry to have the git version in the package version.\r
983 cmd(f,\r
984     name = 'update changelog',\r
985     workdir = 'build/DIST',\r
986     command = [ 'debchange', '-m', '-l', WithProperties('+g%(gitversion)s'), 'Automatically built' ],\r
987 )\r
988 \r
989 cmd(f,\r
990     name = 'source pkg',\r
991     command = [ 'dpkg-buildpackage', '-S', '-us', '-uc' ],\r
992     workdir = 'build/DIST',\r
993 )\r
994 \r
995 for dist in distributions:\r
996     f.addStep(slave.MakeDirectory(dir='build/RESULT-' + dist))\r
997 \r
998 # Create debian sid repository\r
999 f.addStep(slave.MakeDirectory(dir='build/REPO-sid/conf'))\r
1000 f.addStep(transfer.StringDownload(\r
1001     """Codename: precise\r
1002 Suite: unstable\r
1003 Architectures: i386 amd64 source\r
1004 Components: main\r
1005 DebIndices: Packages Release . .gz .bz2\r
1006 DscIndices: Sources Release . .gz .bz2\r
1007 SignWith: %(gpg_key)s\r
1008 """ % { "gpg_key": gpg_key },\r
1009     slavedest = 'REPO-sid/conf/distributions',\r
1010 ))\r
1011 \r
1012 # add source package to repository\r
1013 reprepro_include_ubuntu(f, 'i3-wm*_source.changes', 'dsc')\r
1014 \r
1015 # Add keyring to the repository. We need to run git clone on our own because\r
1016 # the Git() step assumes there’s precisely one repository we want to deal with.\r
1017 # No big deal since the i3-autobuild-keyring repository is not big.\r
1018 cmd(f, name='clone keyring repo', command = 'git clone git://code.i3wm.org/i3-autobuild-keyring')\r
1019 reprepro_include_ubuntu(f, 'i3-autobuild-keyring/prebuilt/*.changes')\r
1020 \r
1021 for dist in distributions:\r
1022     # update the pbuilder\r
1023     cmd(f, name = 'update builder', command = 'pbuilder-' + dist + ' update')\r
1024 \r
1025     # build the package for each dist\r
1026     f.addStep(ShellCommand(\r
1027         logEnviron = False,\r
1028         name = 'pkg ' + dist,\r
1029         command = 'pbuilder-' + dist + ' build --binary-arch \\r
1030 --buildresult RESULT-' + dist + ' --debbuildopts -j8 i3-wm*dsc',\r
1031         warnOnFailure = True\r
1032     ))\r
1033 \r
1034     reprepro_include_ubuntu(f, 'RESULT-' + dist + '/*.changes')\r
1035 \r
1036 # upload the sid repo\r
1037 # Since the next step is cleaning up old files, we set haltOnFailure=True -- we\r
1038 # prefer providing old packages over providing no packages at all :).\r
1039 for directory in [ 'pool', 'dists' ]:\r
1040     f.addStep(transfer.DirectoryUpload(\r
1041         slavesrc = 'REPO-sid/' + directory,\r
1042         masterdest = 'htdocs/ubuntu/precise/' + directory,\r
1043         compress = 'bz2',\r
1044         name = 'upload precise ' + directory,\r
1045         haltOnFailure = True,\r
1046     ))\r
1047 \r
1048 f.addStep(master.MasterShellCommand(\r
1049     command = "find htdocs/ubuntu/precise/pool -mtime +3 -exec rm '{}' \;",\r
1050     name = 'cleanup old packages',\r
1051 ))\r
1052 \r
1053 # We ensure there is an empty i18n/Index to speed up apt (so that it does not\r
1054 # try to download Translation-*)\r
1055 f.addStep(master.MasterShellCommand(\r
1056     command = [ 'mkdir', '-p', 'htdocs/ubuntu/precise/dists/sid/main/i18n' ],\r
1057     name = 'create i18n folder',\r
1058 ))\r
1059 f.addStep(master.MasterShellCommand(\r
1060     command = [ 'touch', 'htdocs/ubuntu/precise/dists/sid/main/i18n/Index' ],\r
1061     name = 'touch i18n/Index',\r
1062 ))\r
1063 \r
1064 \r
1065 c['builders'] = []\r
1066 \r
1067 # Add all builders to all buildslaves.\r
1068 for factoryname in factories.keys():\r
1069     c['builders'].append(BuilderConfig(\r
1070         name = factoryname,\r
1071         slavenames=['docsteel-vm'],\r
1072         factory=factories[factoryname],\r
1073     ))\r
1074 \r
1075 \r
1076 ####### STATUS TARGETS\r
1077 \r
1078 c['status'] = []\r
1079 \r
1080 authz_cfg=authz.Authz(\r
1081     gracefulShutdown = False,\r
1082     forceBuild = False,\r
1083     forceAllBuilds = False,\r
1084     pingBuilder = False,\r
1085     stopBuild = False,\r
1086     stopAllBuilds = False,\r
1087     cancelPendingBuild = False,\r
1088 )\r
1089 \r
1090 c['status'].append(html.WebStatus(http_port=8010, authz=authz_cfg))\r
1091 \r
1092 c['status'].append(buildbot.status.status_push.HttpStatusPush(\r
1093     serverUrl = 'http://localhost:8080/push_buildbot',\r
1094 ))\r
1095 \r
1096 ####### PROJECT IDENTITY\r
1097 \r
1098 c['title'] = 'i3'\r
1099 c['titleURL'] = 'http://i3wm.org/'\r
1100 # Removed so that search engines don’t crawl it\r
1101 c['buildbotURL'] = 'http://localhost/'\r
1102 \r
1103 ####### DB URL\r
1104 \r
1105 c['db'] = {\r
1106     # This specifies what database buildbot uses to store its state.  You can leave\r
1107     # this at its default for all but the largest installations.\r
1108     'db_url' : "sqlite:///state.sqlite",\r
1109 }</tt></pre>\r
1110 </div></div>\r
1111 </div>\r
1112 </div>\r
1113 </div>\r
1114 <div id="footnotes"><hr /></div>\r
1115 <div id="footer" lang="de">\r
1116 © 2009-2011 Michael Stapelberg, <a href="/impress.html">Impressum</a>\r
1117 </div>\r
1118 </body>\r
1119 </html>\r