Merge "Allow zuul to cleanup jobs outside window"
diff --git a/zuul/layoutvalidator.py b/zuul/layoutvalidator.py
index d464998..847bce7 100644
--- a/zuul/layoutvalidator.py
+++ b/zuul/layoutvalidator.py
@@ -61,7 +61,7 @@
                                'subject': str,
                                },
                       }
-    window = v.All(int, v.Range(min=1))
+    window = v.All(int, v.Range(min=0))
     window_floor = v.All(int, v.Range(min=1))
     window_type = v.Any('linear', 'exponential')
     window_factor = v.All(int, v.Range(min=1))
diff --git a/zuul/model.py b/zuul/model.py
index b66480a..cc1817f 100644
--- a/zuul/model.py
+++ b/zuul/model.py
@@ -462,11 +462,11 @@
         self.window = min(self.window, other.window)
         # TODO merge semantics
 
-    def getActionableItems(self):
+    def isActionable(self, item):
         if self.dependent and self.window:
-            return self.queue[:self.window]
+            return item in self.queue[:self.window]
         else:
-            return self.queue[:]
+            return True
 
     def increaseWindowSize(self):
         if self.dependent:
diff --git a/zuul/scheduler.py b/zuul/scheduler.py
index fabaa88..f9d8085 100644
--- a/zuul/scheduler.py
+++ b/zuul/scheduler.py
@@ -1151,10 +1151,11 @@
                 change_queue.moveItem(item, nnfi)
                 changed = True
                 self.cancelJobs(item)
-            self.prepareRef(item)
-            if item.current_build_set.unable_to_merge:
-                failing_reasons.append("it has a merge conflict")
-        if self.launchJobs(item):
+            if change_queue.isActionable(item):
+                self.prepareRef(item)
+                if item.current_build_set.unable_to_merge:
+                    failing_reasons.append("it has a merge conflict")
+        if change_queue.isActionable(item) and self.launchJobs(item):
             changed = True
         if self.pipeline.didAnyJobFail(item):
             failing_reasons.append("at least one job failed")
@@ -1185,7 +1186,7 @@
         for queue in self.pipeline.queues:
             queue_changed = False
             nnfi = None  # Nearest non-failing item
-            for item in queue.getActionableItems():
+            for item in queue.queue[:]:
                 item_changed, nnfi = self._processOneItem(item, nnfi)
                 if item_changed:
                     queue_changed = True