David Schneider avatar David Schneider committed 3eaa460

add a buildstep to extract and update the changeset-id from the revision property of a SourceStamp

Comments (0)

Files changed (2)

bot2/pypybuildbot/builds.py

 from buildbot.steps.source.mercurial import Mercurial
+from buildbot.process.buildstep import BuildStep
 from buildbot.process import factory
 from buildbot.steps import shell, transfer
 from buildbot.steps.trigger import Trigger
 from buildbot.process.properties import WithProperties
 from buildbot import locks
 from pypybuildbot.util import symlink_force
+from buildbot.status.results import SKIPPED, SUCCESS
 import os
 
 # buildbot supports SlaveLocks, which can be used to limit the amout of builds
         builder.saveYourself()
 
 # _______________________________________________________________
+# XXX Currently the build properties got_revision and final_file_name contain
+# the revision number and the changeset-id, CheckGotRevision takes care to set
+# the corresponding build properties
+# rev:changeset for got_revision
+# rev-changeset for final_file_name
+#
+# The rev part of got_revision and filename is used everywhere to sort the
+# builds, i.e. on the summary and download pages.
+#
+# The rev part is strictly local and needs to be removed from the SourceStamp,
+# at least for decoupled builds, which is what ParseRevision does.
+#
+# XXX in general it would be nice to drop the revision-number using only the
+# changeset-id for got_revision and final_file_name and sorting the builds
+# chronologically
 class CheckGotRevision(ShellCmd):
     description = 'got_revision'
     command = ['hg', 'parents', '--template', 'got_revision:{rev}:{node}']
             self.build.setProperty('final_file_name', final_file_name,
                                    'got_revision')
 
+class ParseRevision(BuildStep):
+    """Parse the revision property of the source stamp and extract the global
+    part of the revision
+    123:3a34 -> 3a34"""
+    name = "parse_revision"
+
+    def __init__(self, *args, **kwargs):
+        BuildStep.__init__(self, *args, **kwargs)
+
+    @staticmethod
+    def hideStepIf(results, step):
+        return results==SKIPPED
+
+    @staticmethod
+    def doStepIf(step):
+        revision = step.build.getSourceStamp().revision
+        return isinstance(revision, (unicode, str)) and ':' in revision
+
+    def start(self):
+        stamp = self.build.getSourceStamp()
+        revision = stamp.revision
+        if isinstance(revision, (unicode, str)) and ':' in revision:
+            parts = revision.split(':')
+            self.build.setProperty('revision', parts[1], 'parse_revision')
+            stamp.revision = parts[1]
+            self.finished(SUCCESS)
+
+
 def update_hg(platform, factory, repourl, workdir, use_branch,
               force_branch=None):
     factory.addStep(
         # for debugging
         repourl = '/home/antocuni/pypy/default'
     #
+    factory.addStep(ParseRevision(hideStepIf=ParseRevision.hideStepIf,
+                                  doStepIf=ParseRevision.doStepIf))
+    #
     update_hg(platform, factory, repourl, workdir, use_branch=True,
               force_branch=force_branch)
     #
                                 basename=name + extension,
                                 workdir='.',
                                 blocksize=100 * 1024))
-        if trigger: # if provided trigger schedulers that are depend on this one
+        if trigger: # if provided trigger schedulers that depend on this one
             self.addStep(Trigger(schedulerNames=[trigger]))
 
 

bot2/pypybuildbot/test/test_builds.py

 
 class FakeProperties(object):
 
-    def __init__(self):
-        pass
-    
+    sources = {}
+
+    def __init__(self, properties=None):
+        if properties is None:
+            self.properties = {'branch':None, 'got_revision': 123,
+                    'final_file_name': '123-ea5ca8'}
+        else:
+            self.properties = properties
+
     def __getitem__(self, item):
-        if item == 'branch':
-            return None
-        if item == 'got_revision':
-            return 123
-        if item == 'final_file_name':
-            return '123-ea5ca8'
-    
+        return self.properties.get(item)
+
+    def __setitem__(self, name, value):
+        self.properties[name] = value
+
     def render(self, x):
         return x
 
+class FakeSourceStamp(object):
+    def __init__(self, properties=None):
+        self.properties = properties if properties is not None else {}
+
+    def __getattr__(self, name):
+        return self.properties.get(name)
+
+    def __setattribute__(self, name, value):
+        self.properties[name] = value
+
 class FakeBuild(object):
     slaveEnvironment = None
 
-    def __init__(self):
-        self.properties = FakeProperties()
-    
+    def __init__(self, properties=None):
+        self.properties = FakeProperties(properties)
+        self.source_stamp = FakeSourceStamp(properties)
+
     def getProperties(self):
         return self.properties
 
+    def setProperty(self, name, value, source):
+        self.properties[name] = value
+        self.properties.sources[name] = source
+
     def getSlaveCommandVersion(self, *args):
         return 3
 
+    def getSourceStamp(self, *args):
+        return self.source_stamp
+
 class FakeStepStatus(object):
     def setText(self, *args):
         pass
 
+    def stepFinished(self, results):
+        self.results = results
+
+    def setHidden(self, *args):
+        pass
+
 class FakeDeferred(object):
+    def callback(*args):
+        pass
     def addCallback(self, *args):
         return FakeDeferred()
     def addErrback(self, *args):
         step.commandComplete(cmd)
         summary = builder.summary_by_branch_and_revision[('trunk', '123')]
         assert summary.to_tuple() == (2, 2, 4, 0)
+
+
+class TestParseRevision(object):
+
+    def setup_method(self, mth):
+        inst = builds.ParseRevision()
+        factory = inst._getStepFactory().factory
+        kw = inst._getStepFactory().kwargs
+        self.rebuilt = factory(**kw)
+        self.rebuilt.step_status = FakeStepStatus()
+        self.rebuilt.deferred = FakeDeferred()
+
+    def test_has_revision(self):
+        self.rebuilt.build = FakeBuild({'revision':u'123:ea5ca8'})
+        self.rebuilt.start()
+        assert self.rebuilt.build.getProperties()['revision'] == 'ea5ca8'
+
+    def test_no_revision(self):
+        self.rebuilt.build = FakeBuild()
+        self.rebuilt.start()
+        assert self.rebuilt.build.getProperties()['revision'] is None
+
+    def test_revision_no_local_part(self):
+        self.rebuilt.build = FakeBuild({'revision':u'ea5ca8'})
+        self.rebuilt.start()
+        assert self.rebuilt.build.getProperties()['revision'] == 'ea5ca8'
+
+    def test_empty_revision(self):
+        self.rebuilt.build = FakeBuild({'revision':u''})
+        self.rebuilt.start()
+        assert self.rebuilt.build.getProperties()['revision'] == ''
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.