launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #01912
[Merge] lp:~thumper/launchpad/recipe-binary-builds into lp:launchpad/devel
Tim Penhey has proposed merging lp:~thumper/launchpad/recipe-binary-builds into lp:launchpad/devel.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
#602508 Ignoring binary build outcomes violates user expectations
https://bugs.launchpad.net/bugs/602508
Adds binary build information to the latest builds section on the recipe index page.
http://people.canonical.com/~tim/recipe-latest-builds.png shows an example of how it looks.
I made some of the properties of the view that were accessed multiple times
cached properties. This required a few tweaks in the tests too.
The binary builds for the successful recipe builds are indented slightly and
show underneath the recipe build that they relate to.
During interactive hacking, I found that I wanted some nicer repr methods
for the processors.
A drive-by fix on the soyuz build-index.pt to just specify the content as
buildlog instead of using tal:content="string: buildlog"
--
https://code.launchpad.net/~thumper/launchpad/recipe-binary-builds/+merge/40686
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~thumper/launchpad/recipe-binary-builds into lp:launchpad/devel.
=== modified file 'lib/lp/code/browser/sourcepackagerecipebuild.py'
--- lib/lp/code/browser/sourcepackagerecipebuild.py 2010-08-30 11:51:40 +0000
+++ lib/lp/code/browser/sourcepackagerecipebuild.py 2010-11-12 04:23:29 +0000
@@ -32,6 +32,7 @@
ISourcePackageRecipeBuild,
)
from lp.services.job.interfaces.job import JobStatus
+from lp.services.propertycache import cachedproperty
UNEDITABLE_BUILD_STATES = (
@@ -93,7 +94,7 @@
BuildStatus.FAILEDTOUPLOAD: 'Could not be uploaded correctly',
}.get(self.context.status, self.context.status.title)
- @property
+ @cachedproperty
def eta(self):
"""The datetime when the build job is estimated to complete.
@@ -112,14 +113,14 @@
duration = queue_record.estimated_duration
return start_time + duration
- @property
+ @cachedproperty
def date(self):
"""The date when the build completed or is estimated to complete."""
if self.estimate:
return self.eta
return self.context.date_finished
- @property
+ @cachedproperty
def estimate(self):
"""If true, the date value is an estimate."""
if self.context.date_finished is not None:
=== modified file 'lib/lp/code/browser/tests/test_sourcepackagerecipe.py'
--- lib/lp/code/browser/tests/test_sourcepackagerecipe.py 2010-11-10 20:53:17 +0000
+++ lib/lp/code/browser/tests/test_sourcepackagerecipe.py 2010-11-12 04:23:29 +0000
@@ -42,6 +42,7 @@
from lp.code.interfaces.sourcepackagerecipe import MINIMAL_RECIPE_TEXT
from lp.code.tests.helpers import recipe_parser_newest_version
from lp.registry.interfaces.pocket import PackagePublishingPocket
+from lp.services.propertycache import clear_property_cache
from lp.soyuz.model.processor import ProcessorFamily
from lp.testing import (
ANONYMOUS,
@@ -640,7 +641,7 @@
class TestSourcePackageRecipeView(TestCaseForRecipe):
- layer = DatabaseFunctionalLayer
+ layer = LaunchpadFunctionalLayer
def test_index(self):
recipe = self.makeRecipe()
@@ -673,6 +674,80 @@
# bzr-builder format 0.2 deb-version 0\+\{revno\}
lp://dev/~chef/chocolate/cake""", self.getMainText(recipe))
+ def test_index_success_with_buildlog(self):
+ # The buildlog is shown if it is there.
+ recipe = self.makeRecipe()
+ build = removeSecurityProxy(self.factory.makeSourcePackageRecipeBuild(
+ recipe=recipe, distroseries=self.squirrel, archive=self.ppa))
+ build.status = BuildStatus.FULLYBUILT
+ build.date_started = datetime(2010, 03, 16, tzinfo=utc)
+ build.date_finished = datetime(2010, 03, 16, tzinfo=utc)
+ build.log = self.factory.makeLibraryFileAlias()
+
+ self.assertTextMatchesExpressionIgnoreWhitespace("""\
+ Latest builds
+ Status Time Distribution series Archive
+ Successful build on 2010-03-16 buildlog \(.*\) Secret Squirrel Secret PPA
+ Request build\(s\)""", self.getMainText(recipe))
+
+ def test_index_success_with_binary_builds(self):
+ # Binary builds are shown after the recipe builds if there are any.
+ recipe = self.makeRecipe()
+ build = removeSecurityProxy(self.factory.makeSourcePackageRecipeBuild(
+ recipe=recipe, distroseries=self.squirrel, archive=self.ppa))
+ build.status = BuildStatus.FULLYBUILT
+ build.date_started = datetime(2010, 03, 16, tzinfo=utc)
+ build.date_finished = datetime(2010, 03, 16, tzinfo=utc)
+ build.log = self.factory.makeLibraryFileAlias()
+ package_name = self.factory.getOrMakeSourcePackageName('chocolate')
+ source_package_release = self.factory.makeSourcePackageRelease(
+ archive=self.ppa, sourcepackagename=package_name, distroseries=self.squirrel,
+ source_package_recipe_build=build, version='0+r42')
+ builder = self.factory.makeBuilder()
+ binary_build = self.factory.makeBinaryPackageBuild(
+ source_package_release=source_package_release,
+ distroarchseries=self.squirrel.nominatedarchindep,
+ processor=builder.processor)
+ binary_build.queueBuild()
+
+ self.assertTextMatchesExpressionIgnoreWhitespace("""\
+ Latest builds
+ Status Time Distribution series Archive
+ Successful build on 2010-03-16 buildlog \(.*\) Secret Squirrel Secret PPA
+ chocolate - 0\+r42 starting in .* \(estimated\) i386
+ Request build\(s\)""", self.getMainText(recipe))
+
+ def test_index_success_with_completed_binary_build(self):
+ # Binary builds show their buildlog too.
+ recipe = self.makeRecipe()
+ build = removeSecurityProxy(self.factory.makeSourcePackageRecipeBuild(
+ recipe=recipe, distroseries=self.squirrel, archive=self.ppa))
+ build.status = BuildStatus.FULLYBUILT
+ build.date_started = datetime(2010, 03, 16, tzinfo=utc)
+ build.date_finished = datetime(2010, 03, 16, tzinfo=utc)
+ build.log = self.factory.makeLibraryFileAlias()
+ package_name = self.factory.getOrMakeSourcePackageName('chocolate')
+ source_package_release = self.factory.makeSourcePackageRelease(
+ archive=self.ppa, sourcepackagename=package_name, distroseries=self.squirrel,
+ source_package_recipe_build=build, version='0+r42')
+ builder = self.factory.makeBuilder()
+ binary_build = removeSecurityProxy(self.factory.makeBinaryPackageBuild(
+ source_package_release=source_package_release,
+ distroarchseries=self.squirrel.nominatedarchindep,
+ processor=builder.processor))
+ binary_build.queueBuild()
+ binary_build.status = BuildStatus.FULLYBUILT
+ binary_build.date_started = datetime(2010, 04, 16, tzinfo=utc)
+ binary_build.date_finished = datetime(2010, 04, 16, tzinfo=utc)
+ binary_build.log = self.factory.makeLibraryFileAlias()
+
+ self.assertTextMatchesExpressionIgnoreWhitespace("""\
+ Latest builds
+ Status Time Distribution series Archive
+ Successful build on 2010-03-16 buildlog \(.*\) Secret Squirrel Secret PPA
+ chocolate - 0\+r42 on 2010-04-16 buildlog \(.*\) i386
+ Request build\(s\)""", self.getMainText(recipe))
+
def test_index_no_builds(self):
"""A message should be shown when there are no builds."""
recipe = self.makeRecipe()
@@ -706,7 +781,7 @@
pattern = """\
Latest builds
Status Time Distribution series Archive
- Pending build in .* \(estimated\) Secret Squirrel Secret PPA
+ Pending build starting in .* \(estimated\) Secret Squirrel Secret PPA
Request build\(s\)
Recipe contents"""
@@ -895,8 +970,10 @@
view = self.makeBuildView()
self.assertTrue(view.estimate)
view.context.buildqueue_record.job.start()
+ clear_property_cache(view)
self.assertTrue(view.estimate)
removeSecurityProxy(view.context).date_finished = datetime.now(utc)
+ clear_property_cache(view)
self.assertFalse(view.estimate)
def test_eta(self):
@@ -915,11 +992,13 @@
recipe_build=build)
queue_entry._now = lambda: datetime(1970, 1, 1, 0, 0, 0, 0, utc)
self.factory.makeBuilder()
+ clear_property_cache(view)
self.assertIsNot(None, view.eta)
self.assertEqual(
queue_entry.getEstimatedJobStartTime() +
queue_entry.estimated_duration, view.eta)
queue_entry.job.start()
+ clear_property_cache(view)
self.assertEqual(
queue_entry.job.date_started + queue_entry.estimated_duration,
view.eta)
=== modified file 'lib/lp/code/templates/sourcepackagerecipe-index.pt'
--- lib/lp/code/templates/sourcepackagerecipe-index.pt 2010-11-09 04:24:09 +0000
+++ lib/lp/code/templates/sourcepackagerecipe-index.pt 2010-11-12 04:23:29 +0000
@@ -7,6 +7,13 @@
i18n:domain="launchpad"
>
+<metal:block fill-slot="head_epilogue">
+ <style type="text/css">
+ .binary-build .indent {
+ padding-left: 2em;
+ }
+ </style>
+</metal:block>
<body>
@@ -92,18 +99,36 @@
</tr>
</thead>
<tbody>
- <tr tal:repeat="build view/builds">
+ <tal:recipe-builds repeat="build view/builds">
<tal:build-view define="buildview nocall:build/@@+index">
+ <tr>
<td>
<span tal:replace="structure build/image:icon" />
<a tal:content="buildview/status"
tal:attributes="href build/fmt:url"></a>
</td>
- <td>
- <tal:date replace="buildview/date/fmt:displaydate" />
- <tal:estimate condition="buildview/estimate">
- (estimated)
- </tal:estimate>
+ <td tal:define="is_building build/status/enumvalue:BUILDING">
+ <tal:building condition="is_building">
+ Started
+ <span tal:attributes="title build/date_started/fmt:datetime"
+ tal:content="build/date_started/fmt:approximatedate"
+ >5 minutes ago</span>
+ </tal:building>
+ <tal:not-building condition="not: is_building">
+ <tal:estimate condition="buildview/estimate">
+ starting
+ </tal:estimate>
+ <tal:date replace="buildview/date/fmt:displaydate" />
+ <tal:estimate condition="buildview/estimate">
+ (estimated)
+ </tal:estimate>
+ </tal:not-building>
+ <tal:build-log define="file build/log"
+ tal:condition="file">
+ <a class="sprite download"
+ tal:attributes="href build/log_url">buildlog</a>
+ (<span tal:replace="file/content/filesize/fmt:bytes" />)
+ </tal:build-log>
</td>
<td>
<tal:distro
@@ -112,8 +137,56 @@
<td>
<tal:archive replace="structure build/archive/fmt:link"/>
</td>
- </tal:build-view>
</tr>
+ <tal:binary-builds repeat="binary buildview/binary_builds">
+ <tr tal:define="binaryview nocall:binary/@@+index"
+ class="binary-build">
+ <td class="indent">
+ <span tal:replace="structure binary/image:icon"/>
+ <a tal:content="binary/source_package_release/title"
+ tal:attributes="href binary/fmt:url">package - version</a>
+ </td>
+ <td>
+
+ <tal:pending condition="binaryview/dispatch_time_estimate_available"
+ define="eta binary/buildqueue_record/getEstimatedJobStartTime;">
+ starting <tal:eta
+ replace="eta/fmt:approximatedate">in 3 hours</tal:eta>
+ (estimated)
+ </tal:pending>
+
+ <tal:building condition="binary/status/enumvalue:BUILDING">
+ <li>
+ started
+ <span tal:attributes="title binary/date_started/fmt:datetime"
+ tal:content="binary/date_started/fmt:approximatedate"
+ >5 minutes ago</span>
+ </li>
+ </tal:building>
+
+ <tal:built condition="binary/date_finished">
+ <span tal:attributes="title binary/date_finished/fmt:datetime"
+ tal:content="binary/date_finished/fmt:displaydate">2008-01-01</span>
+ </tal:built>
+
+ <tal:build-log define="file binary/log"
+ tal:condition="file">
+ <a class="sprite download"
+ tal:attributes="href binary/log_url">buildlog</a>
+ (<span tal:replace="file/content/filesize/fmt:bytes" />)
+ </tal:build-log>
+
+ </td>
+ <td class="indent">
+ <a class="sprite distribution"
+ tal:define="archseries binary/distro_arch_series"
+ tal:attributes="href archseries/fmt:url"
+ tal:content="archseries/architecturetag">i386</a>
+ </td>
+ </tr>
+ </tal:binary-builds>
+ </tal:build-view>
+ </tal:recipe-builds>
</tbody>
</table>
<p tal:condition="not: view/builds">
=== modified file 'lib/lp/soyuz/model/processor.py'
--- lib/lp/soyuz/model/processor.py 2010-08-20 20:31:18 +0000
+++ lib/lp/soyuz/model/processor.py 2010-11-12 04:23:29 +0000
@@ -38,6 +38,9 @@
title = StringCol(dbName='title', notNull=True)
description = StringCol(dbName='description', notNull=True)
+ def __repr__(self):
+ return "<Processor %r>" % self.title
+
class ProcessorFamily(SQLBase):
implements(IProcessorFamily)
@@ -55,6 +58,9 @@
return Processor(family=self, name=name, title=title,
description=description)
+ def __repr__(self):
+ return "<ProcessorFamily %r>" % self.title
+
class ProcessorFamilySet:
implements(IProcessorFamilySet)
=== modified file 'lib/lp/soyuz/templates/build-index.pt'
--- lib/lp/soyuz/templates/build-index.pt 2010-08-06 16:01:38 +0000
+++ lib/lp/soyuz/templates/build-index.pt 2010-11-12 04:23:29 +0000
@@ -190,8 +190,7 @@
<li tal:define="file context/log"
tal:condition="file">
<a class="sprite download"
- tal:attributes="href context/log_url"
- tal:content="string: buildlog">BUILDLOG</a>
+ tal:attributes="href context/log_url">buildlog</a>
(<span tal:replace="file/content/filesize/fmt:bytes" />)
</li>
<li tal:define="file context/upload_log"
=== modified file 'lib/lp/testing/factory.py'
--- lib/lp/testing/factory.py 2010-11-05 08:17:29 +0000
+++ lib/lp/testing/factory.py 2010-11-12 04:23:29 +0000
@@ -2696,7 +2696,7 @@
def makeBinaryPackageBuild(self, source_package_release=None,
distroarchseries=None, archive=None, builder=None,
- status=None, pocket=None):
+ status=None, pocket=None, date_created=None, processor=None):
"""Create a BinaryPackageBuild.
If archive is not supplied, the source_package_release is used
@@ -2720,7 +2720,8 @@
self.makeSourcePackagePublishingHistory(
distroseries=source_package_release.upload_distroseries,
archive=archive, sourcepackagerelease=source_package_release)
- processor = self.makeProcessor()
+ if processor is None:
+ processor = self.makeProcessor()
if distroarchseries is None:
distroarchseries = self.makeDistroArchSeries(
distroseries=source_package_release.upload_distroseries,
@@ -2729,6 +2730,8 @@
status = BuildStatus.NEEDSBUILD
if pocket is None:
pocket = PackagePublishingPocket.RELEASE
+ if date_created is None:
+ date_created = self.getUniqueDate()
binary_package_build = getUtility(IBinaryPackageBuildSet).new(
source_package_release=source_package_release,
processor=processor,
@@ -2736,7 +2739,7 @@
status=status,
archive=archive,
pocket=pocket,
- date_created=self.getUniqueDate())
+ date_created=date_created)
naked_build = removeSecurityProxy(binary_package_build)
naked_build.builder = builder
return binary_package_build
Follow ups