Add start actions.

Add the ability to specify a report to gerrit on start.  This
can be used to clear the verified column.

Fixes bug #1012730.

Change-Id: I8dd2a60c3a16a8fa0046675437c750948af99577
diff --git a/doc/source/zuul.rst b/doc/source/zuul.rst
index 9ed4558..d962edb 100644
--- a/doc/source/zuul.rst
+++ b/doc/source/zuul.rst
@@ -163,6 +163,11 @@
 **failure** 
   Uses the same syntax as **success**, but describes what Zuul should
   do if at least one job fails.
+
+**start** 
+  Uses the same syntax as **success**, but describes what Zuul should
+  do when a change is added to the queue manager.  This can be used,
+  for example, to reset the value of the Verified review category.
   
 Some example queue configurations are included in the sample layout
 file.  The first is called a *check* queue::
diff --git a/zuul/lib/gerrit.py b/zuul/lib/gerrit.py
index 648a7bf..13b74fc 100644
--- a/zuul/lib/gerrit.py
+++ b/zuul/lib/gerrit.py
@@ -108,8 +108,9 @@
         return self.event_queue.get()
 
     def review(self, project, change, message, action={}):
-        cmd = 'gerrit review --project %s --message "%s"' % (
-            project, message)
+        cmd = 'gerrit review --project %s' % project
+        if message:
+            cmd += ' --message "%s"' % message
         for k, v in action.items():
             if v is True:
                 cmd += ' --%s' % k
diff --git a/zuul/scheduler.py b/zuul/scheduler.py
index ad0c032..a20db89 100644
--- a/zuul/scheduler.py
+++ b/zuul/scheduler.py
@@ -63,6 +63,7 @@
             self.queue_managers[config_queue['name']] = manager
             manager.success_action = config_queue.get('success')
             manager.failure_action = config_queue.get('failure')
+            manager.start_action = config_queue.get('start')
             for trigger in toList(config_queue['trigger']):
                 approvals = {}
                 for approval_dict in toList(trigger.get('approval')):
@@ -246,6 +247,7 @@
         self.event_filters = []
         self.success_action = {}
         self.failure_action = {}
+        self.start_action = {}
 
     def __str__(self):
         return "<%s %s>" % (self.__class__.__name__, self.name)
@@ -273,6 +275,9 @@
             if p.hasQueue(self.name):
                 self.log.info("    %s" % p)
                 log_jobs(p.getJobTreeForQueue(self.name))
+        if self.start_action:
+            self.log.info("  On start:")
+            self.log.info("    %s" % self.start_action)
         if self.success_action:
             self.log.info("  On success:")
             self.log.info("    %s" % self.success_action)
@@ -288,6 +293,17 @@
 
     def addChange(self, change):
         self.log.debug("Adding change %s" % change)
+        if self.start_action:
+            try:
+                self.log.info("Reporting start, action %s change %s" % (
+                        self.start_action, change))
+                msg = "Starting %s jobs." % self.name
+                ret = self.sched.trigger.report(change, msg, self.start_action)
+                if ret:
+                    self.log.error("Reporting change start %s received: %s" % (
+                            change, ret))
+            except:
+                self.log.exception("Exception while reporting start:")
         self.launchJobs(change)
 
     def launchJobs(self, change):