Merge lp:~cprov/launchpad/bug-430336-builder-status into lp:launchpad

Proposed by Celso Providelo
Status: Merged
Merged at revision: not available
Proposed branch: lp:~cprov/launchpad/bug-430336-builder-status
Merge into: lp:launchpad
Diff against target: None lines
To merge this branch: bzr merge lp:~cprov/launchpad/bug-430336-builder-status
Reviewer Review Type Date Requested Status
Paul Hummer (community) Approve
Review via email: mp+11980@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Celso Providelo (cprov) wrote :

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

= Summary =

This branch primarily replaces the HiddenBuilder hack used to
implicitly hides information about private sources with an more
appropriate and testable mechanism. Both BuilderSet:+index and
Builder:+index use the same template macro for rendering the builder
'status summary' now.

I could also remove `IBuilder.status` implementation entirely, since
it's not needed anymore. The dynamic form is much nicers (includes
icon and link to the building job). I thought it would be nicer to do
it in a separate branch, or at least, after the branch direction gets
approved.

I also took the opportunity to fix
https://bugs.edge.launchpad.net/bugs/430336, now IDLE builder in
manual-mode with state it clear in its 'status-summary'.

== Tests ==

./bin/test -vv -t builder-views.txt -t stories.ppa -t stories.soyuz

== Demo and Q/A ==

1. https://launchpad.dev/builders (log in as foo.bar)
2. 'Register a new build machine' and play with the 'builderok' and
   the 'manual' flag.

= Launchpad lint =

Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.

Linting changed files:
  lib/canonical/launchpad/pagetitles.py
  lib/lp/soyuz/templates/builder-index.pt
  lib/lp/soyuz/stories/soyuz/xx-builder-page.txt
  lib/lp/soyuz/browser/tests/builder-views.txt
  lib/lp/soyuz/stories/soyuz/xx-private-builds.txt
  lib/lp/soyuz/templates/builders-index.pt
  lib/lp/soyuz/browser/builder.py
  lib/lp/soyuz/browser/configure.zcml
  lib/lp/soyuz/stories/soyuz/xx-buildfarm-index.txt
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iEYEARECAAYFAkqyThYACgkQ7KBXuXyZSjBt0wCfegMiSBQgWbi9nbnwoIIc2mvC
SCoAnjXrfd2fkrF1Kw46FUiviRJ+Jwz7
=4ZHJ
-----END PGP SIGNATURE-----

Revision history for this message
Paul Hummer (rockstar) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/canonical/launchpad/pagetitles.py'
2--- lib/canonical/launchpad/pagetitles.py 2009-09-17 10:04:26 +0000
3+++ lib/canonical/launchpad/pagetitles.py 2009-09-17 14:01:16 +0000
4@@ -269,8 +269,6 @@
5
6 build_rescore = ContextTitle('Rescore %s')
7
8-builders_index = 'Launchpad build farm'
9-
10 calendar_index = ContextTitle('%s')
11
12 calendar_event_addform = ContextTitle('Add event to %s')
13
14=== modified file 'lib/lp/soyuz/browser/builder.py'
15--- lib/lp/soyuz/browser/builder.py 2009-09-03 15:04:13 +0000
16+++ lib/lp/soyuz/browser/builder.py 2009-09-17 14:45:15 +0000
17@@ -39,9 +39,7 @@
18 LaunchpadFormView, LaunchpadView, Link, Navigation,
19 StandardLaunchpadFacets, action, canonical_url, custom_widget,
20 enabled_with_permission, stepthrough)
21-from canonical.launchpad.webapp.authorization import check_permission
22 from canonical.launchpad.webapp.breadcrumb import Breadcrumb
23-from lazr.delegates import delegates
24 from canonical.widgets import HiddenUserWidget
25
26
27@@ -120,41 +118,22 @@
28 return Link('+mode', text, icon='edit')
29
30
31-class CommonBuilderView(LaunchpadView):
32- """Common builder methods used in this file."""
33-
34- def overrideHiddenBuilder(self, builder):
35- """Override the builder to HiddenBuilder as necessary.
36-
37- HiddenBuilder is used if the user does not have permission to
38- see the build on the builder.
39- """
40- current_job = builder.currentjob
41- if (current_job and
42- not check_permission('launchpad.View', current_job.build)):
43- # Cloak the builder.
44- return HiddenBuilder(builder)
45- else:
46- # The build is public, don't cloak it.
47- return builder
48-
49-
50-class BuilderSetView(CommonBuilderView):
51- """Default BuilderSet view class
52-
53- Simply provides CommonBuilderView for the BuilderSet pagetemplate.
54- """
55+class BuilderSetView(LaunchpadView):
56+ """Default BuilderSet view class."""
57 __used_for__ = IBuilderSet
58
59+ @property
60+ def label(self):
61+ return self.context.title
62+
63+ @property
64+ def page_title(self):
65+ return self.label
66+
67 @cachedproperty
68 def builders(self):
69- """Return all active builders, with private builds cloaked.
70-
71- Any builders building a private build will be cloaked and returned
72- as a HiddenBuilder.
73- """
74- builders = self.context.getBuilders()
75- return [self.overrideHiddenBuilder(builder) for builder in builders]
76+ """All active builders"""
77+ return list(self.context.getBuilders())
78
79 @property
80 def number_of_registered_builders(self):
81@@ -205,6 +184,7 @@
82 else:
83 self.duration = duration
84
85+
86 class BuilderCategory:
87 """A category of builders.
88
89@@ -246,52 +226,13 @@
90 self._builder_groups.append(builder_group)
91
92
93-class HiddenBuilder:
94- """Overrides a IBuilder building a private job.
95-
96- This class modifies IBuilder attributes that should not be exposed
97- while building a job for private job (private PPA or Security).
98- """
99- delegates(IBuilder)
100-
101- failnotes = None
102- currentjob = None
103- builderok = False
104- status = 'Building private build'
105-
106- def __init__(self, context):
107- self.context = context
108-
109- # This method is required because the builder history page will have this
110- # cloaked context if the builder is currently processing a private build.
111- def getBuildRecords(self, build_state=None, name=None, arch_tag=None,
112- user=None):
113- """See `IHasBuildRecords`."""
114- return self.context.getBuildRecords(
115- build_state, name, arch_tag, user)
116-
117-
118-class BuilderView(CommonBuilderView, BuildRecordsView):
119+class BuilderView(LaunchpadView):
120 """Default Builder view class
121
122 Implements useful actions for the page template.
123 """
124 __used_for__ = IBuilder
125
126- def __init__(self, context, request):
127- context = self.overrideHiddenBuilder(context)
128- super(BuilderView, self).__init__(context, request)
129-
130- @property
131- def default_build_state(self):
132- """Present all jobs by default."""
133- return None
134-
135- @property
136- def show_builder_info(self):
137- """Hide Builder info, see BuildRecordsView for further details"""
138- return False
139-
140 @property
141 def current_build_duration(self):
142 """Return the delta representing the duration of the current job."""
143@@ -318,15 +259,27 @@
144 return "Switch to manual-mode"
145
146
147-class BuilderHistoryView(BuilderView):
148+class BuilderHistoryView(BuildRecordsView):
149 """This class exists only to override the page_title."""
150
151+ __used_for__ = IBuilder
152+
153 @property
154 def page_title(self):
155 """Return a relevant page title for this view."""
156 return smartquote(
157 'Build history for "%s"' % self.context.title)
158
159+ @property
160+ def default_build_state(self):
161+ """Present all jobs by default."""
162+ return None
163+
164+ @property
165+ def show_builder_info(self):
166+ """Hide Builder info, see BuildRecordsView for further details"""
167+ return False
168+
169
170 class BuilderSetAddView(LaunchpadFormView):
171 """View class for adding new Builders."""
172
173=== modified file 'lib/lp/soyuz/browser/configure.zcml'
174--- lib/lp/soyuz/browser/configure.zcml 2009-09-10 12:59:56 +0000
175+++ lib/lp/soyuz/browser/configure.zcml 2009-09-16 19:06:48 +0000
176@@ -425,22 +425,24 @@
177 facet="overview"
178 name="+index"/>
179 <browser:page
180+ template="../templates/builder-portlet-details.pt"
181+ name="+portlet-details"
182+ facet="overview"/>
183+ </browser:pages>
184+ <browser:pages
185+ for="lp.soyuz.interfaces.builder.IBuilder"
186+ permission="zope.Public"
187+ class="lp.soyuz.browser.builder.BuilderHistoryView">
188+ <browser:page
189+ name="+history"
190+ template="../templates/builder-history.pt"
191+ facet="overview" />
192+ <browser:page
193 template="../templates/builds-list.pt"
194 name="+builds-list"
195 facet="overview"/>
196- <browser:page
197- template="../templates/builder-portlet-details.pt"
198- name="+portlet-details"
199- facet="overview"/>
200 </browser:pages>
201 <browser:page
202- name="+history"
203- for="lp.soyuz.interfaces.builder.IBuilder"
204- permission="zope.Public"
205- template="../templates/builder-history.pt"
206- facet="overview"
207- class="lp.soyuz.browser.builder.BuilderHistoryView" />
208- <browser:page
209 name="+edit"
210 for="lp.soyuz.interfaces.builder.IBuilder"
211 class="lp.soyuz.browser.builder.BuilderEditView"
212
213=== modified file 'lib/lp/soyuz/browser/tests/builder-views.txt'
214--- lib/lp/soyuz/browser/tests/builder-views.txt 2009-08-27 19:09:44 +0000
215+++ lib/lp/soyuz/browser/tests/builder-views.txt 2009-09-16 19:06:48 +0000
216@@ -196,9 +196,6 @@
217 >>> empty_request = LaunchpadTestRequest(form={})
218 >>> admin_view = getMultiAdapter((frog, empty_request), name="+index")
219
220- >>> print admin_view.context
221- <security proxied lp.soyuz.model.builder.Builder ...>
222-
223 >>> print admin_view.context.builderok
224 True
225
226@@ -219,36 +216,6 @@
227 >>> print admin_view.current_build_duration
228 10 days...
229
230-When accessing the same view as a unprivileged user, No-Priv, the
231-sensitive information is hidden (the context class is 'cloaked', see
232-browser/builder.py for futher information on this) and the builder
233-shows up as 'Building private build'.
234-
235- >>> login('no-priv@canonical.com')
236- >>> nopriv_view = getMultiAdapter((frog, empty_request), name="+index")
237-
238- >>> print nopriv_view.context
239- <lp.soyuz.browser.builder.HiddenBuilder ...>
240-
241- >>> print nopriv_view.context.builderok
242- False
243-
244- >>> print nopriv_view.context.currentjob
245- None
246-
247- >>> print nopriv_view.context.failnotes
248- None
249-
250- >>> print nopriv_view.context.status
251- Building private build
252-
253- >>> print nopriv_view.current_build_duration
254- None
255-
256-XXX cprov 20080214: this is clearly a counterintuitive way to identify
257-builders building private jobs. We will certainly have to fine-tune it
258-before public release.
259-
260 Once the private job is gone, Frog 'real' details are exposed publicly
261 again.
262
263
264=== modified file 'lib/lp/soyuz/stories/soyuz/xx-builder-page.txt'
265--- lib/lp/soyuz/stories/soyuz/xx-builder-page.txt 2009-09-12 06:49:56 +0000
266+++ lib/lp/soyuz/stories/soyuz/xx-builder-page.txt 2009-09-17 14:45:15 +0000
267@@ -17,7 +17,7 @@
268 >>> print extract_text(find_portlet(
269 ... anon_browser.contents, 'View full history Current status'))
270 View full history Current status
271- i386 build of mozilla-firefox 0.9 in ubuntu hoary RELEASE
272+ Building i386 build of mozilla-firefox 0.9 in ubuntu hoary RELEASE
273 Started ... ago.
274 Buildlog
275 Dummy sampledata entry, not processing
276@@ -31,7 +31,7 @@
277 >>> print extract_text(find_portlet(
278 ... user_browser.contents, 'View full history Current status'))
279 View full history Current status
280- i386 build of mozilla-firefox 0.9 in ubuntu hoary RELEASE
281+ Building i386 build of mozilla-firefox 0.9 in ubuntu hoary RELEASE
282 Started ... ago.
283 Buildlog
284 Dummy sampledata entry, not processing
285@@ -214,6 +214,7 @@
286 >>> cprov_browser.getLink("Build Farm").click()
287
288 >>> print extract_text(find_main_content(cprov_browser.contents))
289+ The Launchpad build farm
290 Register a new build machine
291 0 available build machines, 1 disabled and 0 building of a total
292 of 1 registered.
293
294=== modified file 'lib/lp/soyuz/stories/soyuz/xx-buildfarm-index.txt'
295--- lib/lp/soyuz/stories/soyuz/xx-buildfarm-index.txt 2009-09-10 22:08:36 +0000
296+++ lib/lp/soyuz/stories/soyuz/xx-buildfarm-index.txt 2009-09-17 14:45:15 +0000
297@@ -13,6 +13,7 @@
298 containing the build queue status summary for each build domain.
299
300 >>> print extract_text(find_main_content(anon_browser.contents))
301+ The Launchpad build farm
302 1 available build machine, 1 disabled and 1 building of a total of
303 2 registered.
304 Builders
305@@ -26,6 +27,13 @@
306 Processor Builders Queue
307 386 0 empty
308
309+When building, the 'Status' column contains a link to the
310+corresponding 'Build' page.
311+
312+ >>> print anon_browser.getLink(
313+ ... 'i386 build of mozilla-firefox 0.9').url
314+ http://launchpad.dev/ubuntu/+source/mozilla-firefox/0.9/+build/8
315+
316 The build status portlets contain the number of builds waiting
317 in queue and the sum of their 'estimated_build_duration' for each
318 supported processor on each separated build domain, 'official'
319
320=== modified file 'lib/lp/soyuz/stories/soyuz/xx-private-builds.txt'
321--- lib/lp/soyuz/stories/soyuz/xx-private-builds.txt 2009-09-10 22:32:06 +0000
322+++ lib/lp/soyuz/stories/soyuz/xx-private-builds.txt 2009-09-17 14:45:15 +0000
323@@ -58,24 +58,23 @@
324 >>> logout()
325
326 So now we can go to frog's builder page and see what the page shows us.
327-The status shown to an anonymous user hides the fact that it's building a
328-private build:
329+The status shown to an anonymous user hides the private source it is
330+building.
331
332 >>> anon_browser.open("http://launchpad.dev/+builds/frog")
333 >>> print extract_text(find_main_content(anon_browser.contents))
334 The frog builder...
335 Current status
336- The frog builder
337- is deactivated.
338+ Building private source
339 ...
340
341-
342 Launchpad Administrators are allowed to see the build:
343
344 >>> admin_browser.open("http://launchpad.dev/+builds/frog")
345 >>> print extract_text(find_main_content(admin_browser.contents))
346 The frog builder...
347 Current status
348+ Building
349 i386 build of privacy-test 666 in ubuntutest breezy-autotest RELEASE
350 ...
351
352@@ -86,7 +85,7 @@
353 >>> print extract_text(find_main_content(name12_browser.contents))
354 The frog builder...
355 Current status
356- The frog builder is deactivated.
357+ Building private source
358 ...
359
360 cprov is also allowed to see his own build:
361@@ -97,6 +96,7 @@
362 >>> print extract_text(find_main_content(cprov_browser.contents))
363 The frog builder...
364 Current status
365+ Building
366 i386 build of privacy-test 666 in ubuntutest breezy-autotest RELEASE
367 ...
368
369@@ -229,7 +229,7 @@
370
371 >>> admin_browser.open("http://launchpad.dev/+builds")
372 >>> print extract_text(find_main_content(admin_browser.contents))
373- Register a new build machine
374+ The Launchpad build farm
375 ...
376 Name Processor Status
377 bob 386 Building i386 build of mozilla-firefox ...
378@@ -240,18 +240,18 @@
379
380 >>> name12_browser.open("http://launchpad.dev/+builds")
381 >>> print extract_text(find_main_content(name12_browser.contents))
382- Register a new build machine
383+ The Launchpad build farm
384 ...
385 Name Processor Status
386 bob 386 Building i386 build of mozilla-firefox ...
387- frog 386 Building private build
388+ frog 386 Building private source
389 ...
390
391 cprov can see his own private build:
392
393 >>> cprov_browser.open("http://launchpad.dev/+builds")
394 >>> print extract_text(find_main_content(cprov_browser.contents))
395- Register a new build machine
396+ The Launchpad build farm
397 ...
398 Name Processor Status
399 bob 386 Building i386 build of mozilla-firefox ...
400@@ -262,11 +262,12 @@
401
402 >>> anon_browser.open("http://launchpad.dev/+builds")
403 >>> print extract_text(find_main_content(anon_browser.contents))
404- 1 available build machine, ...
405+ The Launchpad build farm
406+ 2 available build machines, ...
407 ...
408 Name Processor Status
409 bob 386 Building i386 build of mozilla-firefox ...
410- frog 386 Building private build
411+ frog 386 Building private source
412 ...
413
414
415@@ -326,7 +327,7 @@
416 >>> anon_browser = setupBrowser()
417 >>> anon_browser.open("http://launchpad.dev/+builds")
418 >>> print extract_text(find_main_content(anon_browser.contents))
419- 2 available build machines, ...
420+ The Launchpad build farm
421 ...
422 Name Processor Status
423 bob 386 Building i386 build of mozilla-firefox ...
424@@ -337,7 +338,7 @@
425
426 >>> browser.open("http://launchpad.dev/+builds")
427 >>> print extract_text(find_main_content(browser.contents))
428- 2 available build machines, ...
429+ The Launchpad build farm
430 ...
431 Name Processor Status
432 bob 386 Building i386 build of mozilla-firefox ...
433
434=== modified file 'lib/lp/soyuz/templates/builder-index.pt'
435--- lib/lp/soyuz/templates/builder-index.pt 2009-08-19 20:00:00 +0000
436+++ lib/lp/soyuz/templates/builder-index.pt 2009-09-16 19:06:48 +0000
437@@ -29,46 +29,11 @@
438 </p>
439 </div>
440 <div class="yui-ge">
441+
442 <div class="first yui-u">
443- <div class="portlet">
444- <h2>
445- <span class="see-all"><a
446- tal:replace="structure view/menu:overview/history/fmt:link" />
447- </span>
448- Current status</h2>
449+ <div metal:use-macro="template/macros/status" />
450+ </div><!-- yui-u -->
451
452- <tal:no_job condition="not: job">
453- <p><tal:builder content="context/title" />
454- <tal:builderok condition="context/builderok"
455- >is idle.</tal:builderok>
456- <tal:buildernok condition="not: context/builderok"
457- >is deactivated.</tal:buildernok></p>
458- </tal:no_job>
459- <tal:job condition="job">
460- <tal:icon replace="structure job/build/image:icon" />
461- <a tal:attributes="href job/build/fmt:url">
462- <span tal:replace="job/build/title">NAME</span>
463- </a>
464- <p class="sprite">Started
465- <span tal:attributes="title job/buildstart/fmt:datetime"
466- tal:content="view/current_build_duration/fmt:exactduration"
467- />
468- ago.
469- </p>
470- <tal:logtail condition="job/logtail">
471- <h3>Buildlog</h3>
472- <div tal:content="structure job/logtail/fmt:text-to-html"
473- id="buildlog-tail" class="logtail">
474- Things are crashing and burning all over the place.
475- </div>
476- <p class="discreet" tal:condition="view/user">
477- Updated on
478- <span tal:replace="structure view/user/fmt:local-time"/>
479- </p>
480- </tal:logtail>
481- </tal:job>
482- </div><!-- portlet -->
483- </div><!-- yui-u -->
484 <div class="yui-u">
485 <div class="portlet">
486 <h2>Builder information</h2>
487@@ -111,5 +76,106 @@
488 <tal:menu replace="structure view/@@+related-pages" />
489 </div>
490 </div>
491+
492+
493+<metal:macros fill-slot="bogus">
494+
495+ <metal:macro define-macro="status-summary">
496+ <tal:comment replace="nothing">
497+ Status summary.
498+ :param builder: IBuilder, context builder.
499+ :param job: IBuildQueue, job assigned to the builder.
500+ </tal:comment>
501+
502+ <tal:no_job condition="not: job">
503+ <tal:builderok condition="builder/builderok">
504+ <tal:idle condition="not: builder/manual">
505+ <span class="sortkey" tal:content="string:0" />
506+ <span class="sprite yes green">Idle</span>
507+ </tal:idle>
508+ <tal:manual tal:condition="builder/manual">
509+ <span class="sortkey" tal:content="string:1" />
510+ <span class="sprite info">Manual</span>
511+ </tal:manual>
512+ </tal:builderok>
513+ <tal:buildernok condition="not: builder/builderok">
514+ <span class="sortkey" tal:content="string:2" />
515+ <span class="sprite no red">Disabled</span>
516+ </tal:buildernok>
517+ </tal:no_job>
518+
519+ <tal:job condition="job">
520+ <span class="sortkey" tal:content="job/id" />
521+ <tal:build define="build job/build">
522+ <tal:visible condition="build/required:launchpad.View">
523+ <tal:icon replace="structure build/image:icon" />
524+ Building
525+ <a tal:attributes="href build/fmt:url"
526+ tal:content="build/title"
527+ >i386 build of mozilla-firefox 0.9 in ubuntu hoary RELEASE</a>
528+ <tal:ppa condition="build/archive/is_ppa"
529+ define="ppa build/archive;">
530+ <span tal:replace="string: [${ppa/owner/name}/${ppa/name}]"
531+ >[cprov/ppa]</span>
532+ </tal:ppa>
533+ </tal:visible>
534+ <tal:restricted condition="not: build/required:launchpad.View">
535+ <img src="/@@/processing" alt="[building]" />
536+ Building private source
537+ </tal:restricted>
538+ </tal:build>
539+ </tal:job>
540+
541+ </metal:macro>
542+
543+
544+ <metal:macro define-macro="status">
545+ <tal:comment replace="nothing">
546+ Status summary.
547+ :param job: IBuildQueue, job assigned to the context builder.
548+ </tal:comment>
549+
550+ <div class="portlet">
551+ <h2>
552+ <span class="see-all"><a
553+ tal:replace="structure view/menu:overview/history/fmt:link" />
554+ </span>
555+ Current status</h2>
556+
557+ <p tal:define="builder context">
558+ <metal:summary use-macro="template/macros/status-summary" />
559+ </p>
560+
561+ <tal:buildernok condition="not: context/builderok">
562+ <div tal:content="structure
563+ context/failnotes/fmt:text-to-html" />
564+ </tal:buildernok>
565+
566+ <tal:job condition="job">
567+ <p class="sprite">Started
568+ <span tal:attributes="title job/buildstart/fmt:datetime"
569+ tal:content="view/current_build_duration/fmt:exactduration"
570+ /> ago.</p>
571+ <tal:visible condition="job/build/required:launchpad.View">
572+ <tal:logtail condition="job/logtail">
573+ <h3>Buildlog</h3>
574+ <div tal:content="structure job/logtail/fmt:text-to-html"
575+ id="buildlog-tail" class="logtail">
576+ Things are crashing and burning all over the place.
577+ </div>
578+ <p class="discreet" tal:condition="view/user">
579+ Updated on
580+ <span tal:replace="structure view/user/fmt:local-time"/>
581+ </p>
582+ </tal:logtail>
583+ </tal:visible>
584+ </tal:job>
585+ </div>
586+
587+ </metal:macro>
588+
589+</metal:macros>
590+
591+
592 </body>
593 </html>
594
595=== modified file 'lib/lp/soyuz/templates/builders-index.pt'
596--- lib/lp/soyuz/templates/builders-index.pt 2009-08-29 05:15:41 +0000
597+++ lib/lp/soyuz/templates/builders-index.pt 2009-09-16 18:53:46 +0000
598@@ -75,21 +75,8 @@
599 >386</tal:processor>
600 </td>
601 <td tal:define="job builder/currentjob">
602- <tal:not-building condition="not: job">
603- <tal:idle condition="builder/builderok">
604- <span class="sortkey" tal:content="string:1" />
605- <img src="/@@/yes" alt="[idle]" title="Idle" />
606- </tal:idle>
607- <tal:broken condition="not: builder/builderok">
608- <span class="sortkey" tal:content="string:0" />
609- <img src="/@@/no" alt="[disabled]" title="Disabled" />
610- </tal:broken>
611- </tal:not-building>
612- <tal:building condition="job">
613- <span class="sortkey" tal:content="job/id" />
614- <tal:icon replace="structure job/build/image:icon" />
615- </tal:building>
616- <tal:status replace="builder/status">Buiding fooo</tal:status>
617+ <metal:status-summary
618+ use-macro="builder/@@+index/status-summary" />
619 </td>
620 </tr>
621 </tbody>