Added collapse build requests handling.
diff --git a/zorg/buildbot/process/buildrequest.py b/zorg/buildbot/process/buildrequest.py
new file mode 100644
index 0000000..7af49a1
--- /dev/null
+++ b/zorg/buildbot/process/buildrequest.py
@@ -0,0 +1,69 @@
+from twisted.internet import defer
+
+@defer.inlineCallbacks
+def collapseRequests(master, builder, req1, req2):
+ """
+ Returns true if both buildrequest can be merged, via Deferred.
+
+ This implements Zorg's default collapse strategy.
+ """
+ # If these are for the same buildset, collapse away
+ if req1['buildsetid'] == req2['buildsetid']:
+ return True
+
+ # Get the buidlsets for each buildrequest
+ selfBuildsets = yield master.data.get(
+ ('buildsets', str(req1['buildsetid'])))
+ otherBuildsets = yield master.data.get(
+ ('buildsets', str(req2['buildsetid'])))
+
+ # extract sourcestamps, as dictionaries by codebase
+ selfSources = dict((ss['codebase'], ss)
+ for ss in selfBuildsets['sourcestamps'])
+ otherSources = dict((ss['codebase'], ss)
+ for ss in otherBuildsets['sourcestamps'])
+
+ # if the sets of codebases do not match, we can't collapse
+ if set(selfSources) != set(otherSources):
+ return False
+
+ for c, selfSS in selfSources.items():
+ otherSS = otherSources[c]
+ if selfSS['repository'] != otherSS['repository']:
+ return False
+
+ if selfSS['branch'] != otherSS['branch']:
+ return False
+
+ # TODO: Handle projects matching if we ever would have
+ # a mix of projects from the monorepo and outside of
+ # the monorepo. For now, we consider all of them being
+ # a part of the monorepo, so all of them are compatible
+ # and could be collapsed.
+
+ # anything with a patch won't be collapsed
+ if selfSS['patch'] or otherSS['patch']:
+ return False
+
+ # get changes & compare
+ selfChanges = yield master.data.get(('sourcestamps', selfSS['ssid'], 'changes'))
+ otherChanges = yield master.data.get(('sourcestamps', otherSS['ssid'], 'changes'))
+ # if both have changes, proceed, else fail - if no changes check revision instead
+ if selfChanges and otherChanges:
+ continue
+
+ if selfChanges and not otherChanges:
+ return False
+
+ if not selfChanges and otherChanges:
+ return False
+
+ # else check revisions
+ if selfSS['revision'] != otherSS['revision']:
+ return False
+
+ # Build requests with different reasons should be built separately.
+ if req1.get('reason', None) == req2.get('reason', None):
+ return True
+ else:
+ return False