hooks: only start tests on new public revisions (closes #2741838) stable
authorJulien Cristau <julien.cristau@logilab.fr>
Tue, 12 Mar 2013 16:20:36 +0100
branchstable
changeset 878 601c4a1f8c53
parent 877 86cc30266cd5
child 879 58359ab60f98
hooks: only start tests on new public revisions (closes #2741838) Tests should be run if - a new public revision is addded, or - an existing draft revision is made public. Use an operation to group both cases, called from two separate hooks.
__pkginfo__.py
debian/control
hooks.py
--- a/__pkginfo__.py	Mon Mar 11 18:11:20 2013 +0100
+++ b/__pkginfo__.py	Tue Mar 12 16:20:36 2013 +0100
@@ -21,7 +21,7 @@
 
 __depends__ = {'pyro': None,
                'cubicweb': '>= 3.14.0',
-               'cubicweb-vcsfile': '>= 1.6.1',
+               'cubicweb-vcsfile': '>= 1.12',
                'cubicweb-file': None,
                'cubicweb-narval': '>= 3.0.2',
                }
--- a/debian/control	Mon Mar 11 18:11:20 2013 +0100
+++ b/debian/control	Tue Mar 12 16:20:36 2013 +0100
@@ -13,7 +13,7 @@
 Package: cubicweb-apycot
 Architecture: all
 XB-Python-Version: ${python:Versions}
-Depends: ${misc:Depends}, ${python:Depends}, cubicweb-common (>= 3.14.0), cubicweb-vcsfile (>= 1.6.1), cubicweb-file (>= 1.8.2), cubicweb-narval (>= 3.0.2), pyro
+Depends: ${misc:Depends}, ${python:Depends}, cubicweb-common (>= 3.14.0), cubicweb-vcsfile (>= 1.12), cubicweb-file (>= 1.8.2), cubicweb-narval (>= 3.0.2), pyro
 Recommends: cubicweb-jqplot (>= 0.1.2)
 Suggests: cubicweb-tracker, cubicweb-nosylist (>= 0.5.0)
 Description: apycot component for the CubicWeb framework
--- a/hooks.py	Mon Mar 11 18:11:20 2013 +0100
+++ b/hooks.py	Tue Mar 12 16:20:36 2013 +0100
@@ -122,6 +122,64 @@
         self.repo.looping_task(60*60, check_test_to_start, self.repo)
 
 
+class StartTestOp(hook.Operation):
+    def precommit_event(self):
+        for revision in self.get_data():
+            vcsrepo = revision.repository
+            for basepe in vcsrepo.reverse_local_repository:
+                for pe in basepe.iter_refinements():
+                    if pe.vcs_path:
+                        # start test only if the revision is modifying file under
+                        # specified directory.
+                        if not self._cw.execute(
+                            'Any R LIMIT 1 WHERE R eid %(r)s, VC from_revision R,'
+                            'VC content_for VF, VF directory ~= %(path)s',
+                            {'r': revision.eid, 'path': pe.vcs_path + '%'}):
+                            continue
+                    for tc in pe.iter_configurations('on new revision'):
+                        if tc.match_branch(pe, revision.branch):
+                            # check recipe, we don't want buggy config to block
+                            # creation of the revision
+                            if tc.recipe:
+                                tc.start(pe, revision.branch)
+                            else:
+                                self.error('expected to start test config %s for '
+                                           'revision with %s but it has no recipe',
+                                           tc, revision)
+            # when a test is started, it may use some revision of dependency's
+            # repositories that may not be already imported by vcsfile. So when it
+            # try to create a link between the execution and the revision, it
+            # fails. In such case the information is kept as a CheckResultInfo
+            # object, use it to create the link later when the changeset is
+            # imported.
+            done = set()
+            for cri in self._cw.execute(
+                'Any CRI, X WHERE CRI for_check X, CRI type "revision", '
+                'CRI label ~= %(repo)s, CRI value %(cs)s',
+                {'cs': revision.changeset,
+                 # safety belt in case of duplicated short changeset. XXX useful?
+                 'repo': '%s:%s%%' % (vcsrepo.type, vcsrepo.source_url or vcsrepo.path),
+                 }).entities():
+                # safety belt to avoid crash if relation is already set. In some
+                # dark cases we end up with several version information about the
+                # same project on the same check result...
+                if cri.check_result.eid not in done:
+                    cri.check_result.set_relations(using_revision=revision)
+                    done.add(cri.check_result.eid)
+                cri.cw_delete()
+
+
+class StartTestAfterPublicRevision(hook.Hook):
+    __regid__ = 'apycot.start_test_on_public_rev'
+    __select__ = hook.Hook.__select__ & is_instance('Revision') & ~session.repairing()
+    events = ('before_update_entity',)
+
+    def __call__(self):
+        revision = self.entity
+        if 'phase' not in revision.cw_edited or revision.cw_edited['phase'] != 'public':
+            return
+        StartTestOp.get_instance(self._cw).add_data(revision)
+
 class StartTestAfterAddRevision(hook.Hook):
     __regid__ = 'apycot.start_test_on_new_rev'
     __select__ = hook.Hook.__select__ & is_instance('Revision') & ~session.repairing()
@@ -129,48 +187,9 @@
 
     def __call__(self):
         revision = self.entity
-        vcsrepo = revision.repository
-        for basepe in vcsrepo.reverse_local_repository:
-            for pe in basepe.iter_refinements():
-                if pe.vcs_path:
-                    # start test only if the revision is modifying file under
-                    # specified directory.
-                    if not self._cw.execute(
-                        'Any R LIMIT 1 WHERE R eid %(r)s, VC from_revision R,'
-                        'VC content_for VF, VF directory ~= %(path)s',
-                        {'r': revision.eid, 'path': pe.vcs_path + '%'}):
-                        continue
-                for tc in pe.iter_configurations('on new revision'):
-                    if tc.match_branch(pe, revision.branch):
-                        # check recipe, we don't want buggy config to block
-                        # creation of the revision
-                        if tc.recipe:
-                            tc.start(pe, revision.branch)
-                        else:
-                            self.error('expected to start test config %s for '
-                                       'revision with %s but it has no recipe',
-                                       tc, revision)
-        # when a test is started, it may use some revision of dependency's
-        # repositories that may not be already imported by vcsfile. So when it
-        # try to create a link between the execution and the revision, it
-        # fails. In such case the information is kept as a CheckResultInfo
-        # object, use it to create the link later when the changeset is
-        # imported.
-        done = set()
-        for cri in self._cw.execute(
-            'Any CRI, X WHERE CRI for_check X, CRI type "revision", '
-            'CRI label ~= %(repo)s, CRI value %(cs)s',
-            {'cs': revision.changeset,
-             # safety belt in case of duplicated short changeset. XXX useful?
-             'repo': '%s:%s%%' % (vcsrepo.type, vcsrepo.source_url or vcsrepo.path),
-             }).entities():
-            # safety belt to avoid crash if relation is already set. In some
-            # dark cases we end up with several version information about the
-            # same project on the same check result...
-            if cri.check_result.eid not in done:
-                cri.check_result.set_relations(using_revision=revision)
-                done.add(cri.check_result.eid)
-            cri.cw_delete()
+        if revision.phase != 'public':
+            return
+        StartTestOp.get_instance(self._cw).add_data(revision)
 
 
 # notifications ################################################################