)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"f7c09adf786c8bc819cafddfd6e0aa3d89942ef7","unresolved":false,"context_lines":[{"line_number":12,"context_line":"that result."},{"line_number":13,"context_line":""},{"line_number":14,"context_line":"This also copies some exceptions.MergeFailure cleanup from change"},{"line_number":15,"context_line":"I38b4fac4868a823b0de2f6c505744a927c577fad."},{"line_number":16,"context_line":""},{"line_number":17,"context_line":"Change-Id: I1c9db6993994bf8e841ecd8554c37a3ec0afc798"},{"line_number":18,"context_line":"Story: 2000773"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":9,"id":"ffe62b97_1fc3153a","line":15,"updated":"2017-03-28 17:24:16.000000000","message":"If so, you should add a Co-Authored-By footer.","commit_id":"cd51f68615d6b9c47fc12cfd74c2e5a75c490e63"}],"tests/base.py":[{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"e636a8bfb3f09fc59cc738346a6301c8e5b0898e","unresolved":false,"context_lines":[{"line_number":777,"context_line":"        if not commit:  # merge conflict"},{"line_number":778,"context_line":"            result \u003d dict(result\u003d\u0027MERGER_FAILURE\u0027)"},{"line_number":779,"context_line":"            self.job.sendWorkComplete(json.dumps(result))"},{"line_number":780,"context_line":"            self.recordResult(\u0027MERGER_FAILURE\u0027)"},{"line_number":781,"context_line":"        return commit"},{"line_number":782,"context_line":""},{"line_number":783,"context_line":"    def recordResult(self, result):"}],"source_content_type":"text/x-python","patch_set":8,"id":"ffe62b97_bf0c29a5","line":780,"updated":"2017-03-28 17:25:00.000000000","message":"We can call the superclass doMergeChanges and then record MERGER_FAILURE if commit is None.  That way we don\u0027t have to copy as much of the \"real\" code.","commit_id":"1b29ad026c56a736caa4caacd1d545b8fcbdaa71"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"0f0453e774149ffdc8c848fdc3bebece961d5e9e","unresolved":false,"context_lines":[{"line_number":737,"context_line":"        self.log.debug(\"Releasing build %s (%s)\" % (regex,"},{"line_number":738,"context_line":"                                                    len(self.running_builds)))"},{"line_number":739,"context_line":"        for build in builds:"},{"line_number":740,"context_line":"            if not regex or re.match(regex, getattr(build, match)):"},{"line_number":741,"context_line":"                self.log.debug(\"Releasing build %s\" %"},{"line_number":742,"context_line":"                               (build.parameters[\u0027ZUUL_UUID\u0027]))"},{"line_number":743,"context_line":"                build.release()"}],"source_content_type":"text/x-python","patch_set":18,"id":"dfeb2761_24014f06","line":740,"updated":"2017-04-04 17:05:50.000000000","message":"This part of the change isn\u0027t really needed anymore, but I guess we can keep it if you want.","commit_id":"e8c00539077906bbe9b7c647d7fa2efb3e2a90c8"}],"tests/unit/test_scheduler.py":[{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"8c04427fc6c74a9260fce4943b91fc469c156274","unresolved":false,"context_lines":[{"line_number":978,"context_line":"    def test_delayed_merge_conflict(self):"},{"line_number":979,"context_line":"        \"Test that delayed check merge conflicts are handled properly\""},{"line_number":980,"context_line":""},{"line_number":981,"context_line":"        self.executor_server.hold_jobs_in_build \u003d True"},{"line_number":982,"context_line":"        A \u003d self.fake_gerrit.addFakeChange(\u0027org/project\u0027,"},{"line_number":983,"context_line":"                                           \u0027master\u0027, \u0027A\u0027,"},{"line_number":984,"context_line":"                                           files\u003d{\u0027conflict\u0027: \u0027foo\u0027})"}],"source_content_type":"text/x-python","patch_set":16,"id":"dfeb2761_0fa32d51","line":981,"updated":"2017-04-03 18:22:31.000000000","message":"What this test wants to do is make sure that A merges before the executor performs the merges for the jobs in B and C.  We want to pause B and C mid-process while A reports and is merged upstream.  Holding the building job in the executor server, which is what this line does, will pause the build after the executor merges, during the ansible portion of the run.  So instead, we need to pause things right before the executor does anything with the build (since the merge happens right at the start).  To do that, we should hold them in the gearman queue.","commit_id":"0ce807bd3555afca806060aa5b9eef57e5a1dcfa"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"8c04427fc6c74a9260fce4943b91fc469c156274","unresolved":false,"context_lines":[{"line_number":1002,"context_line":"        self.assertEqual(C.reported, 0)  # Check does not report start"},{"line_number":1003,"context_line":""},{"line_number":1004,"context_line":"        # A merges while B and C are queued in check"},{"line_number":1005,"context_line":"        self.executor_server.release(\u00271,1\u0027, match\u003d\u0027changes\u0027)"},{"line_number":1006,"context_line":"        self.waitUntilSettled()"},{"line_number":1007,"context_line":"        self.executor_server.release(\u00271,1\u0027, match\u003d\u0027changes\u0027)"},{"line_number":1008,"context_line":"        self.waitUntilSettled()"}],"source_content_type":"text/x-python","patch_set":16,"id":"dfeb2761_ef8929ca","line":1005,"updated":"2017-04-03 18:22:31.000000000","message":"We don\u0027t have as many nice helper functions for releasing things in the gearman queue.  We can still release by job name, but that isn\u0027t specific enough here.  But if we\u0027re careful in the test, the order is deterministic, so we can start by releasing project-merge for A, which we know is at the head.","commit_id":"0ce807bd3555afca806060aa5b9eef57e5a1dcfa"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"8c04427fc6c74a9260fce4943b91fc469c156274","unresolved":false,"context_lines":[{"line_number":1004,"context_line":"        # A merges while B and C are queued in check"},{"line_number":1005,"context_line":"        self.executor_server.release(\u00271,1\u0027, match\u003d\u0027changes\u0027)"},{"line_number":1006,"context_line":"        self.waitUntilSettled()"},{"line_number":1007,"context_line":"        self.executor_server.release(\u00271,1\u0027, match\u003d\u0027changes\u0027)"},{"line_number":1008,"context_line":"        self.waitUntilSettled()"},{"line_number":1009,"context_line":""},{"line_number":1010,"context_line":"        self.assertEqual(A.data[\u0027status\u0027], \u0027MERGED\u0027)"}],"source_content_type":"text/x-python","patch_set":16,"id":"dfeb2761_cf8425b4","line":1007,"updated":"2017-04-03 18:22:31.000000000","message":"Once project-merge completes for A, Zuul launches project-test1 and project-test2.  Because the gate pipeline has precedence set to high, those two jobs get added to the head of the queue, in front of the project-merge jobs for B and C.  So we can just release the first two jobs.","commit_id":"0ce807bd3555afca806060aa5b9eef57e5a1dcfa"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"8c04427fc6c74a9260fce4943b91fc469c156274","unresolved":false,"context_lines":[{"line_number":1021,"context_line":""},{"line_number":1022,"context_line":"        # B and C report merge conflicts"},{"line_number":1023,"context_line":"        self.executor_server.hold_jobs_in_queue \u003d False"},{"line_number":1024,"context_line":"        self.executor_server.release()"},{"line_number":1025,"context_line":"        self.waitUntilSettled()"},{"line_number":1026,"context_line":""},{"line_number":1027,"context_line":"        self.assertEqual(A.data[\u0027status\u0027], \u0027MERGED\u0027)"}],"source_content_type":"text/x-python","patch_set":16,"id":"dfeb2761_af9321fa","line":1024,"updated":"2017-04-03 18:22:31.000000000","message":"At this point, the only jobs left to run are the B and C project-merge jobs.  We expect them to fail, and therefore, Zuul will not enqueue the project-test jobs for those changes.  They are already in the right order, so we can just release the remaining gearman queue.","commit_id":"0ce807bd3555afca806060aa5b9eef57e5a1dcfa"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"8c04427fc6c74a9260fce4943b91fc469c156274","unresolved":false,"context_lines":[{"line_number":1040,"context_line":"            dict(name\u003d\u0027project-test2\u0027, result\u003d\u0027MERGER_FAILURE\u0027, changes\u003d\u00272,1\u0027),"},{"line_number":1041,"context_line":"            dict(name\u003d\u0027project-merge\u0027, result\u003d\u0027MERGER_FAILURE\u0027, changes\u003d\u00272,1 3,1\u0027),"},{"line_number":1042,"context_line":"            dict(name\u003d\u0027project-test1\u0027, result\u003d\u0027MERGER_FAILURE\u0027, changes\u003d\u00272,1 3,1\u0027),"},{"line_number":1043,"context_line":"            dict(name\u003d\u0027project-test2\u0027, result\u003d\u0027MERGER_FAILURE\u0027, changes\u003d\u00272,1 3,1\u0027),"},{"line_number":1044,"context_line":"        ], ordered\u003dFalse)"},{"line_number":1045,"context_line":""},{"line_number":1046,"context_line":"    def test_post(self):"}],"source_content_type":"text/x-python","patch_set":16,"id":"dfeb2761_8f8e1dce","line":1043,"updated":"2017-04-03 18:22:31.000000000","message":"Because the test1 and test2 jobs depend on merge, they are never launched when merge fails.","commit_id":"0ce807bd3555afca806060aa5b9eef57e5a1dcfa"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"0f0453e774149ffdc8c848fdc3bebece961d5e9e","unresolved":false,"context_lines":[{"line_number":927,"context_line":"    def test_project_merge_conflict(self):"},{"line_number":928,"context_line":"        \"Test that gate merge conflicts are handled properly\""},{"line_number":929,"context_line":""},{"line_number":930,"context_line":"        self.executor_server.hold_jobs_in_build \u003d True"},{"line_number":931,"context_line":"        A \u003d self.fake_gerrit.addFakeChange(\u0027org/project\u0027,"},{"line_number":932,"context_line":"                                           \u0027master\u0027, \u0027A\u0027,"},{"line_number":933,"context_line":"                                           files\u003d{\u0027conflict\u0027: \u0027foo\u0027})"}],"source_content_type":"text/x-python","patch_set":18,"id":"dfeb2761_6905f013","line":930,"updated":"2017-04-04 17:05:50.000000000","message":"This changes from holding in queue to holding in build, but I think that should be okay.","commit_id":"e8c00539077906bbe9b7c647d7fa2efb3e2a90c8"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"0f0453e774149ffdc8c848fdc3bebece961d5e9e","unresolved":false,"context_lines":[{"line_number":955,"context_line":"        self.executor_server.release(\u0027project-merge\u0027)"},{"line_number":956,"context_line":"        self.waitUntilSettled()"},{"line_number":957,"context_line":""},{"line_number":958,"context_line":"        self.executor_server.hold_jobs_in_queue \u003d False"},{"line_number":959,"context_line":"        self.executor_server.release()"},{"line_number":960,"context_line":"        self.waitUntilSettled()"},{"line_number":961,"context_line":""}],"source_content_type":"text/x-python","patch_set":18,"id":"dfeb2761_49022c0d","line":958,"updated":"2017-04-04 17:05:50.000000000","message":"-1: This should be \"_build\".","commit_id":"e8c00539077906bbe9b7c647d7fa2efb3e2a90c8"}],"zuul/manager/__init__.py":[{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"e636a8bfb3f09fc59cc738346a6301c8e5b0898e","unresolved":false,"context_lines":[{"line_number":336,"context_line":"            tenant \u003d self.pipeline.layout.tenant"},{"line_number":337,"context_line":"            zuul_driver.onChangeEnqueued(tenant, item.change, self.pipeline)"},{"line_number":338,"context_line":"            if isinstance(item.change, Change):"},{"line_number":339,"context_line":"                self.scheduleMerge(item)"},{"line_number":340,"context_line":"            return True"},{"line_number":341,"context_line":""},{"line_number":342,"context_line":"    def dequeueItem(self, item):"}],"source_content_type":"text/x-python","patch_set":8,"id":"ffe62b97_ffd4f1ea","line":339,"updated":"2017-03-28 17:25:00.000000000","message":"This will only cause the merge to happen when the change is enqueued.  However, the merge is part of the NNFI algorithm.  It needs to happen every time the queue sequence is changed.  Therefore, it needs to be called from within _processOneItem.","commit_id":"1b29ad026c56a736caa4caacd1d545b8fcbdaa71"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"e636a8bfb3f09fc59cc738346a6301c8e5b0898e","unresolved":false,"context_lines":[{"line_number":524,"context_line":"                return None"},{"line_number":525,"context_line":"            return self._loadDynamicLayout(item)"},{"line_number":526,"context_line":"        self.log.debug(\"Preparing dynamic layout for: %s\" % item.change)"},{"line_number":527,"context_line":"        self.scheduleMerge(item, [\u0027zuul.yaml\u0027, \u0027.zuul.yaml\u0027])"},{"line_number":528,"context_line":""},{"line_number":529,"context_line":"    def scheduleMerge(self, item, files\u003dNone):"},{"line_number":530,"context_line":"        self.log.debug(\"Scheduling merge for item %s (files: %s)\" %"}],"source_content_type":"text/x-python","patch_set":8,"id":"ffe62b97_df07ed81","line":527,"updated":"2017-03-28 17:25:00.000000000","message":"We\u0027re trying to make sure this happens for every change, not just changes where the config is updated.  So by the time we get to this method, we should expect to have completed the merge already, rather than trying to schedule it from within here.","commit_id":"1b29ad026c56a736caa4caacd1d545b8fcbdaa71"},{"author":{"_account_id":6039,"name":"Joni Harker","email":"code@gentlydownthe.net","username":"jesusaurus"},"change_message_id":"28df751a5e95dc33c7989ce1701ddf60f4732d04","unresolved":false,"context_lines":[{"line_number":569,"context_line":"            if item.live:"},{"line_number":570,"context_line":"                try:"},{"line_number":571,"context_line":"                    self.reportItem(item)"},{"line_number":572,"context_line":"                except exceptions.MergeFailure:"},{"line_number":573,"context_line":"                    pass"},{"line_number":574,"context_line":"            return (True, nnfi)"},{"line_number":575,"context_line":"        dep_items \u003d self.getFailingDependentItems(item)"}],"source_content_type":"text/x-python","patch_set":11,"id":"ffe62b97_323de3c3","side":"PARENT","line":572,"updated":"2017-03-28 22:17:35.000000000","message":"Oh, I had taken that comment to mean the confusion was on the part of the original author who added these try blocks. If we need to handle these exceptions I will revert this portion of the change.","commit_id":"8f1da2bdef6f9d0833670a8e9404f2fac46d0f2b"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"23f920e216e6ae747bc6e2305d97d41eaebe1787","unresolved":false,"context_lines":[{"line_number":569,"context_line":"            if item.live:"},{"line_number":570,"context_line":"                try:"},{"line_number":571,"context_line":"                    self.reportItem(item)"},{"line_number":572,"context_line":"                except exceptions.MergeFailure:"},{"line_number":573,"context_line":"                    pass"},{"line_number":574,"context_line":"            return (True, nnfi)"},{"line_number":575,"context_line":"        dep_items \u003d self.getFailingDependentItems(item)"}],"source_content_type":"text/x-python","patch_set":11,"id":"ffe62b97_f2f09b93","side":"PARENT","line":572,"updated":"2017-03-28 22:35:40.000000000","message":"Oh, yeah, sorry.  What I mean to say is that this use of the word \"merge\" is not the same use of the word \"merge\" in the rest of this change.\n\nHere, this is dealing with moving the git branch pointer to a new commit.  That is, actually merging the change into the upstream git repo.  In a \"gate\" pipeline, that happens when an item is reported, and if that process fails, then it invalidates all the items behind it and we have a gate reset.  So this (and more importantly, the one below it) handle that case.\n\nThe rest of this change is about the local speculative merge that happens before we start testing a change.  We end up using the word \"merge\" for both of them since it\u0027s the same git operation.","commit_id":"8f1da2bdef6f9d0833670a8e9404f2fac46d0f2b"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"7b51c1df33ab4c3a0ebc93aba60532cf57c9cb55","unresolved":false,"context_lines":[{"line_number":569,"context_line":"            if item.live:"},{"line_number":570,"context_line":"                try:"},{"line_number":571,"context_line":"                    self.reportItem(item)"},{"line_number":572,"context_line":"                except exceptions.MergeFailure:"},{"line_number":573,"context_line":"                    pass"},{"line_number":574,"context_line":"            return (True, nnfi)"},{"line_number":575,"context_line":"        dep_items \u003d self.getFailingDependentItems(item)"}],"source_content_type":"text/x-python","patch_set":11,"id":"ffe62b97_dc4250ab","side":"PARENT","line":572,"updated":"2017-03-28 21:43:57.000000000","message":"Why is this being removed?  Is this copied over from I38b4fac4868a823b0de2f6c505744a927c577fad?  If so, please see my comment on that change on why it needs to stay.","commit_id":"8f1da2bdef6f9d0833670a8e9404f2fac46d0f2b"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"7b51c1df33ab4c3a0ebc93aba60532cf57c9cb55","unresolved":false,"context_lines":[{"line_number":610,"context_line":"            self.dequeueItem(item)"},{"line_number":611,"context_line":"            changed \u003d True"},{"line_number":612,"context_line":"        if ((not item_ahead) and item.areAllJobsComplete() and item.live):"},{"line_number":613,"context_line":"            try:"},{"line_number":614,"context_line":"                self.reportItem(item)"},{"line_number":615,"context_line":"            except exceptions.MergeFailure:"},{"line_number":616,"context_line":"                failing_reasons.append(\"it did not merge\")"}],"source_content_type":"text/x-python","patch_set":11,"id":"ffe62b97_bc154c9e","side":"PARENT","line":613,"updated":"2017-03-28 21:43:57.000000000","message":"Same comment as above.","commit_id":"8f1da2bdef6f9d0833670a8e9404f2fac46d0f2b"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"7b51c1df33ab4c3a0ebc93aba60532cf57c9cb55","unresolved":false,"context_lines":[{"line_number":721,"context_line":"                self.log.debug(\"%s window size decreased to %s\" %"},{"line_number":722,"context_line":"                               (change_queue, change_queue.window))"},{"line_number":723,"context_line":"                raise exceptions.MergeFailure("},{"line_number":724,"context_line":"                    \"Change %s failed to merge\" % item.change)"},{"line_number":725,"context_line":"            else:"},{"line_number":726,"context_line":"                change_queue.increaseWindowSize()"},{"line_number":727,"context_line":"                self.log.debug(\"%s window size increased to %s\" %"}],"source_content_type":"text/x-python","patch_set":11,"id":"ffe62b97_5c1080a8","side":"PARENT","line":724,"updated":"2017-03-28 21:43:57.000000000","message":"Same comment as above.","commit_id":"8f1da2bdef6f9d0833670a8e9404f2fac46d0f2b"},{"author":{"_account_id":6039,"name":"Joni Harker","email":"code@gentlydownthe.net","username":"jesusaurus"},"change_message_id":"28df751a5e95dc33c7989ce1701ddf60f4732d04","unresolved":false,"context_lines":[{"line_number":513,"context_line":"        # This item updates the config, ask the merger for the result."},{"line_number":514,"context_line":"        build_set \u003d item.current_build_set"},{"line_number":515,"context_line":"        if build_set.merge_state \u003d\u003d build_set.NEW:"},{"line_number":516,"context_line":"            self.scheduleMerge(item, [\u0027zuul.yaml\u0027, \u0027.zuul.yaml\u0027])"},{"line_number":517,"context_line":"            return None"},{"line_number":518,"context_line":"        if build_set.merge_state \u003d\u003d build_set.PENDING:"},{"line_number":519,"context_line":"            return None"}],"source_content_type":"text/x-python","patch_set":11,"id":"ffe62b97_721feb5a","line":516,"updated":"2017-03-28 22:17:35.000000000","message":"We have only scheduled a merged if we got here from prepareItem, but not if we got here from reEnqueueItem. (And I\u0027m not sure what code paths lead to reEnqueueItem.)","commit_id":"9b8456a1855a60e3b559529b4eae4ea9d835b4e5"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"7b51c1df33ab4c3a0ebc93aba60532cf57c9cb55","unresolved":false,"context_lines":[{"line_number":513,"context_line":"        # This item updates the config, ask the merger for the result."},{"line_number":514,"context_line":"        build_set \u003d item.current_build_set"},{"line_number":515,"context_line":"        if build_set.merge_state \u003d\u003d build_set.NEW:"},{"line_number":516,"context_line":"            self.scheduleMerge(item, [\u0027zuul.yaml\u0027, \u0027.zuul.yaml\u0027])"},{"line_number":517,"context_line":"            return None"},{"line_number":518,"context_line":"        if build_set.merge_state \u003d\u003d build_set.PENDING:"},{"line_number":519,"context_line":"            return None"}],"source_content_type":"text/x-python","patch_set":11,"id":"ffe62b97_3c401ca5","line":516,"updated":"2017-03-28 21:43:57.000000000","message":"We shouldn\u0027t schedule a second merge here, it was already done in prepareItem.","commit_id":"9b8456a1855a60e3b559529b4eae4ea9d835b4e5"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"7b51c1df33ab4c3a0ebc93aba60532cf57c9cb55","unresolved":false,"context_lines":[{"line_number":543,"context_line":"        if not build_set.ref:"},{"line_number":544,"context_line":"            build_set.setConfiguration()"},{"line_number":545,"context_line":"        if build_set.merge_state \u003d\u003d build_set.NEW:"},{"line_number":546,"context_line":"            self.scheduleMerge(item)"},{"line_number":547,"context_line":"            return False"},{"line_number":548,"context_line":"        if not build_set.layout:"},{"line_number":549,"context_line":"            build_set.layout \u003d self.getLayout(item)"}],"source_content_type":"text/x-python","patch_set":11,"id":"ffe62b97_1c3d582a","line":546,"updated":"2017-03-28 21:43:57.000000000","message":"I think you want to request the config files here so we only perform one merge.","commit_id":"9b8456a1855a60e3b559529b4eae4ea9d835b4e5"},{"author":{"_account_id":6039,"name":"Joni Harker","email":"code@gentlydownthe.net","username":"jesusaurus"},"change_message_id":"28df751a5e95dc33c7989ce1701ddf60f4732d04","unresolved":false,"context_lines":[{"line_number":553,"context_line":"            return False"},{"line_number":554,"context_line":"        return True"},{"line_number":555,"context_line":""},{"line_number":556,"context_line":"    def prepareJobs(self, item):"},{"line_number":557,"context_line":"        if not item.job_graph:"},{"line_number":558,"context_line":"            try:"},{"line_number":559,"context_line":"                item.freezeJobGraph()"}],"source_content_type":"text/x-python","patch_set":11,"id":"ffe62b97_5224e7ae","line":556,"updated":"2017-03-28 22:17:35.000000000","message":"I was thinking that we could catch merge failures early (as soon as the change is queued), but delay freezing the job graph until the item is actionable (inside the pipeline\u0027s window). This would save us from re-calculating job graphs for queued changes.","commit_id":"9b8456a1855a60e3b559529b4eae4ea9d835b4e5"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"23f920e216e6ae747bc6e2305d97d41eaebe1787","unresolved":false,"context_lines":[{"line_number":553,"context_line":"            return False"},{"line_number":554,"context_line":"        return True"},{"line_number":555,"context_line":""},{"line_number":556,"context_line":"    def prepareJobs(self, item):"},{"line_number":557,"context_line":"        if not item.job_graph:"},{"line_number":558,"context_line":"            try:"},{"line_number":559,"context_line":"                item.freezeJobGraph()"}],"source_content_type":"text/x-python","patch_set":11,"id":"ffe62b97_12f89f78","line":556,"updated":"2017-03-28 22:35:40.000000000","message":"Oh, interesting.  I think that can work.","commit_id":"9b8456a1855a60e3b559529b4eae4ea9d835b4e5"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"7b51c1df33ab4c3a0ebc93aba60532cf57c9cb55","unresolved":false,"context_lines":[{"line_number":553,"context_line":"            return False"},{"line_number":554,"context_line":"        return True"},{"line_number":555,"context_line":""},{"line_number":556,"context_line":"    def prepareJobs(self, item):"},{"line_number":557,"context_line":"        if not item.job_graph:"},{"line_number":558,"context_line":"            try:"},{"line_number":559,"context_line":"                item.freezeJobGraph()"}],"source_content_type":"text/x-python","patch_set":11,"id":"ffe62b97_fc4514b5","line":556,"updated":"2017-03-28 21:43:57.000000000","message":"You could keep this as part of prepareItem, right?  Why split it?","commit_id":"9b8456a1855a60e3b559529b4eae4ea9d835b4e5"},{"author":{"_account_id":6039,"name":"Joni Harker","email":"code@gentlydownthe.net","username":"jesusaurus"},"change_message_id":"28df751a5e95dc33c7989ce1701ddf60f4732d04","unresolved":false,"context_lines":[{"line_number":612,"context_line":"            if item.current_build_set.config_error:"},{"line_number":613,"context_line":"                failing_reasons.append(\"it has an invalid configuration\")"},{"line_number":614,"context_line":"            if actionable and ready:"},{"line_number":615,"context_line":"                jobs_ready \u003d self.prepareJobs(item)"},{"line_number":616,"context_line":"                if jobs_ready and self.provisionNodes(item):"},{"line_number":617,"context_line":"                    changed \u003d True"},{"line_number":618,"context_line":"        if jobs_ready and self.executeJobs(item):"}],"source_content_type":"text/x-python","patch_set":11,"id":"ffe62b97_123adfca","line":615,"updated":"2017-03-28 22:17:35.000000000","message":"By splitting this up, we can run prepareItem before actionable is True, but I wanted to wait until the change is actionable before freezing the job graph. I haven\u0027t looked at that code, I\u0027m just assuming it\u0027s computationally heavy; this could very well be premature optimization.","commit_id":"9b8456a1855a60e3b559529b4eae4ea9d835b4e5"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"7b51c1df33ab4c3a0ebc93aba60532cf57c9cb55","unresolved":false,"context_lines":[{"line_number":612,"context_line":"            if item.current_build_set.config_error:"},{"line_number":613,"context_line":"                failing_reasons.append(\"it has an invalid configuration\")"},{"line_number":614,"context_line":"            if actionable and ready:"},{"line_number":615,"context_line":"                jobs_ready \u003d self.prepareJobs(item)"},{"line_number":616,"context_line":"                if jobs_ready and self.provisionNodes(item):"},{"line_number":617,"context_line":"                    changed \u003d True"},{"line_number":618,"context_line":"        if jobs_ready and self.executeJobs(item):"}],"source_content_type":"text/x-python","patch_set":11,"id":"ffe62b97_9c1a88c9","line":615,"updated":"2017-03-28 21:43:57.000000000","message":"If you kept this as part of prepareItem, we can drop the extra jobs_ready variable and this gets a little simpler.","commit_id":"9b8456a1855a60e3b559529b4eae4ea9d835b4e5"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"23f920e216e6ae747bc6e2305d97d41eaebe1787","unresolved":false,"context_lines":[{"line_number":612,"context_line":"            if item.current_build_set.config_error:"},{"line_number":613,"context_line":"                failing_reasons.append(\"it has an invalid configuration\")"},{"line_number":614,"context_line":"            if actionable and ready:"},{"line_number":615,"context_line":"                jobs_ready \u003d self.prepareJobs(item)"},{"line_number":616,"context_line":"                if jobs_ready and self.provisionNodes(item):"},{"line_number":617,"context_line":"                    changed \u003d True"},{"line_number":618,"context_line":"        if jobs_ready and self.executeJobs(item):"}],"source_content_type":"text/x-python","patch_set":11,"id":"ffe62b97_d2ed97b7","line":615,"updated":"2017-03-28 22:35:40.000000000","message":"It\u0027s something, but it\u0027s not too heavy (by zuul standards).  If you were to do it, putting layout generation in here would probably make sense (it is heavier).\n\nI think the main argument against doing this, however, is that the status page won\u0027t be able to display what jobs are going to be run until this happens.  Maybe that\u0027s okay for an item outside of the window.  I\u0027m willing to try it and see.  :)","commit_id":"9b8456a1855a60e3b559529b4eae4ea9d835b4e5"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"7b51c1df33ab4c3a0ebc93aba60532cf57c9cb55","unresolved":false,"context_lines":[{"line_number":642,"context_line":"                                  (item_behind.change, item))"},{"line_number":643,"context_line":"                    self.cancelJobs(item_behind)"},{"line_number":644,"context_line":"                self.dequeueItem(item)"},{"line_number":645,"context_line":"                changed \u003d True"},{"line_number":646,"context_line":"        return (changed, nnfi)"},{"line_number":647,"context_line":""},{"line_number":648,"context_line":"    def processQueue(self):"}],"source_content_type":"text/x-python","patch_set":11,"id":"ffe62b97_7c0b447c","line":645,"updated":"2017-03-28 21:43:57.000000000","message":"This would report before it reaches the top of the queue which isn\u0027t right.  The previous location for this code is correct.","commit_id":"9b8456a1855a60e3b559529b4eae4ea9d835b4e5"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"00b9b8f281246996feb19ce735ce723535fe4858","unresolved":false,"context_lines":[{"line_number":513,"context_line":"            else:"},{"line_number":514,"context_line":"                return item.queue.pipeline.layout"},{"line_number":515,"context_line":"        # This item updates the config, ask the merger for the result."},{"line_number":516,"context_line":"        build_set \u003d item.current_build_set"},{"line_number":517,"context_line":"        if build_set.merge_state \u003d\u003d build_set.NEW:"},{"line_number":518,"context_line":"            self.scheduleMerge(item, [\u0027zuul.yaml\u0027, \u0027.zuul.yaml\u0027])"},{"line_number":519,"context_line":"            return None"}],"source_content_type":"text/x-python","patch_set":13,"id":"dfeb2761_e0499760","line":516,"updated":"2017-03-30 22:07:38.000000000","message":"We shouldn\u0027t need to scheduleMerge here anymore since it\u0027s handled by prepareItem which is called before this.  In fact, we can probably drop most of the state machine logic from this now.","commit_id":"16b40e3be2308ec90cd91750d63854a9bd745431"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"0efcacdcc2c37b96cebb49b51fc5e05879d15bd8","unresolved":false,"context_lines":[{"line_number":519,"context_line":"            return None"},{"line_number":520,"context_line":"        if build_set.merge_state \u003d\u003d build_set.PENDING:"},{"line_number":521,"context_line":"            return None"},{"line_number":522,"context_line":"        if build_set.merge_state \u003d\u003d build_set.COMPLETE:"},{"line_number":523,"context_line":"            if build_set.unable_to_merge:"},{"line_number":524,"context_line":"                return None"},{"line_number":525,"context_line":"            self.log.debug(\"Preparing dynamic layout for: %s\" % item.change)"}],"source_content_type":"text/x-python","patch_set":13,"id":"dfeb2761_5e9dc457","line":522,"updated":"2017-03-30 23:43:23.000000000","message":"As you pointed out in IRC, this can be called during a re-enqueue.  We don\u0027t need to schedule a merge in that case, but we do need to return None if we\u0027re still waiting on one.  So we should at least keep this stanza, then return None otherwise.","commit_id":"16b40e3be2308ec90cd91750d63854a9bd745431"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"a678edbba0567879bcd32fd53be93856874eac8b","unresolved":false,"context_lines":[{"line_number":529,"context_line":"        if not hasattr(item.change, \u0027branch\u0027):"},{"line_number":530,"context_line":"            self.log.info(\"Change %s does not have an associated branch, \""},{"line_number":531,"context_line":"                          \"not scheduling a merge job for item %s\" %"},{"line_number":532,"context_line":"                          (item.change, item))"},{"line_number":533,"context_line":"            return"},{"line_number":534,"context_line":""},{"line_number":535,"context_line":"        self.log.debug(\"Scheduling merge for item %s (files: %s)\" %"}],"source_content_type":"text/x-python","patch_set":13,"id":"dfeb2761_e301a1b1","line":532,"updated":"2017-03-30 22:55:23.000000000","message":"Strike the first paragraph of the above comment, it\u0027s wrong.","commit_id":"16b40e3be2308ec90cd91750d63854a9bd745431"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"00b9b8f281246996feb19ce735ce723535fe4858","unresolved":false,"context_lines":[{"line_number":529,"context_line":"        if not hasattr(item.change, \u0027branch\u0027):"},{"line_number":530,"context_line":"            self.log.info(\"Change %s does not have an associated branch, \""},{"line_number":531,"context_line":"                          \"not scheduling a merge job for item %s\" %"},{"line_number":532,"context_line":"                          (item.change, item))"},{"line_number":533,"context_line":"            return"},{"line_number":534,"context_line":""},{"line_number":535,"context_line":"        self.log.debug(\"Scheduling merge for item %s (files: %s)\" %"}],"source_content_type":"text/x-python","patch_set":13,"id":"dfeb2761_c0469350","line":532,"updated":"2017-03-30 22:07:38.000000000","message":"The current code will schedule a merge and fetch the new layout even for Refs (which include post pipeline items as well as, now, periodic pipeline items).  This only performs speculative merging and layout collection for Change objects.  I think that\u0027s fine -- I can\u0027t think of a case where it would make a difference (in all cases, the layout configuration these items would run with should be the currently loaded configuration).\n\nHowever, when this is called from pepareItem, if the item is a Ref, the algorithm will get stuck.  prepareItem always expects a speculative merge to happen, but this only causes it to happen for Changes.  We can probably set the buildset state to COMPLETE here, and then return a boolean value to tell prepareItem that it can proceed (since normally it immediately returns false after calling this method).\n\n(BTW, once we get this working, I think it\u0027s worth a look at moving scheduleMerge from pepareItem to prepareJobs).","commit_id":"16b40e3be2308ec90cd91750d63854a9bd745431"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"0f0453e774149ffdc8c848fdc3bebece961d5e9e","unresolved":false,"context_lines":[{"line_number":526,"context_line":"        build_set \u003d item.current_build_set"},{"line_number":527,"context_line":""},{"line_number":528,"context_line":"        if not hasattr(item.change, \u0027branch\u0027):"},{"line_number":529,"context_line":"            self.log.info(\"Change %s does not have an associated branch, \""},{"line_number":530,"context_line":"                          \"not scheduling a merge job for item %s\" %"},{"line_number":531,"context_line":"                          (item.change, item))"},{"line_number":532,"context_line":"            build_set.merge_state \u003d build_set.COMPLETE"}],"source_content_type":"text/x-python","patch_set":18,"id":"dfeb2761_04064b1e","line":529,"updated":"2017-04-04 17:05:50.000000000","message":"This should probably be debug level; it\u0027s not especially interesting for normal operation.","commit_id":"e8c00539077906bbe9b7c647d7fa2efb3e2a90c8"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"0f0453e774149ffdc8c848fdc3bebece961d5e9e","unresolved":false,"context_lines":[{"line_number":609,"context_line":"            # This change is entering the pipeline\u0027s window,"},{"line_number":610,"context_line":"            # schedule a new merge because the previous merge"},{"line_number":611,"context_line":"            # may not be up-to-date."},{"line_number":612,"context_line":"            ready \u003d self.scheduleMerge(item, [\u0027zuul.yaml\u0027, \u0027.zuul.yaml\u0027])"},{"line_number":613,"context_line":"        item.active \u003d actionable"},{"line_number":614,"context_line":""},{"line_number":615,"context_line":"        dep_items \u003d self.getFailingDependentItems(item)"}],"source_content_type":"text/x-python","patch_set":18,"id":"dfeb2761_e406c71c","line":612,"updated":"2017-04-04 17:05:50.000000000","message":"-1: This doesn\u0027t seem right -- why wouldn\u0027t it be up to date?  prepareItem should take care of ensuring that scheduleMerge is called.  We should be able to drop this entire conditional block.","commit_id":"e8c00539077906bbe9b7c647d7fa2efb3e2a90c8"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"1bfad7d2b5436fc1c832c6ac3d2ccffb3d1063ae","unresolved":false,"context_lines":[{"line_number":609,"context_line":"            # This change is entering the pipeline\u0027s window,"},{"line_number":610,"context_line":"            # schedule a new merge because the previous merge"},{"line_number":611,"context_line":"            # may not be up-to-date."},{"line_number":612,"context_line":"            ready \u003d self.scheduleMerge(item, [\u0027zuul.yaml\u0027, \u0027.zuul.yaml\u0027])"},{"line_number":613,"context_line":"        item.active \u003d actionable"},{"line_number":614,"context_line":""},{"line_number":615,"context_line":"        dep_items \u003d self.getFailingDependentItems(item)"}],"source_content_type":"text/x-python","patch_set":18,"id":"dfeb2761_bf168a54","line":612,"updated":"2017-04-04 17:57:51.000000000","message":"Oh, I thought the delayed merge case was testing that the executor could correctly throw a merge error when the state changed out from under it.  I believe that is what it is actually testing (I don\u0027t think that test ever has an item outside the active window).\n\nI\u0027d like to solve that race condition by having the executor merger create the exact same merge as this one.  But that can be done later.\n\nEither way (now or with the change I just described) the condition you describe is not much of a concern.  In a dependent pipeline, the entire future state of all repositories is known and fixed, so there can be no change between when an item crosses into the active window.  In an independent pipeline, the window does not have an effect (all queues are one change deep).  Therefore, in all cases, we should only need one merge check here.\n\nYou make a good argument that we may want to perform the merge earlier, however, in all cases we don\u0027t report a merge conflict until it hits the top of the queue anyway.  We would, however, be able to indicate that it has a merge conflict on the status page earlier.  Still, delayed merging is the current behavior, and we only have *more* work to do in Zuulv3, so I\u0027d rather keep it that way for now.","commit_id":"e8c00539077906bbe9b7c647d7fa2efb3e2a90c8"},{"author":{"_account_id":6039,"name":"Joni Harker","email":"code@gentlydownthe.net","username":"jesusaurus"},"change_message_id":"8cf2e8296824f475096a36fd43175d48563be825","unresolved":false,"context_lines":[{"line_number":609,"context_line":"            # This change is entering the pipeline\u0027s window,"},{"line_number":610,"context_line":"            # schedule a new merge because the previous merge"},{"line_number":611,"context_line":"            # may not be up-to-date."},{"line_number":612,"context_line":"            ready \u003d self.scheduleMerge(item, [\u0027zuul.yaml\u0027, \u0027.zuul.yaml\u0027])"},{"line_number":613,"context_line":"        item.active \u003d actionable"},{"line_number":614,"context_line":""},{"line_number":615,"context_line":"        dep_items \u003d self.getFailingDependentItems(item)"}],"source_content_type":"text/x-python","patch_set":18,"id":"dfeb2761_df3eee89","line":612,"updated":"2017-04-04 17:41:28.000000000","message":"This is needed for the test_delayed_merge_conflict case. Since we scheduled the first merge job when the item first entered the pipeline, and we have no other way of knowing if the change can still merge unless we schedule a second merge job, I think we need to schedule two merges per item. This is less than ideal, but I think it\u0027s needed in order to report merge conflicts before the item is actionable -- which is very useful when queue times are over an hour.","commit_id":"e8c00539077906bbe9b7c647d7fa2efb3e2a90c8"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"0f0453e774149ffdc8c848fdc3bebece961d5e9e","unresolved":false,"context_lines":[{"line_number":629,"context_line":"                              \"item, %s\" % (item.change, item_ahead, nnfi))"},{"line_number":630,"context_line":"                change_queue.moveItem(item, nnfi)"},{"line_number":631,"context_line":"                changed \u003d True"},{"line_number":632,"context_line":"                self.cancelJobs(item)"},{"line_number":633,"context_line":"            if item.current_build_set.unable_to_merge:"},{"line_number":634,"context_line":"                failing_reasons.append(\"it has a merge conflict\")"},{"line_number":635,"context_line":"            if item.current_build_set.config_error:"}],"source_content_type":"text/x-python","patch_set":18,"id":"dfeb2761_c40bc321","line":632,"updated":"2017-04-04 17:05:50.000000000","message":"-1: We\u0027re actually doing more work outside the active window now.  Previously, we would only call prepareLayout (which ran the merge job) when the item was in the active window.  Now we call prepareItem (which runs the merge job) above, outside the active window.\n\nI think if you kept to the current structure, and put prepareItem within the \"if actionable\" block that was here, it would be more efficient.","commit_id":"e8c00539077906bbe9b7c647d7fa2efb3e2a90c8"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"1bfad7d2b5436fc1c832c6ac3d2ccffb3d1063ae","unresolved":false,"context_lines":[{"line_number":629,"context_line":"                              \"item, %s\" % (item.change, item_ahead, nnfi))"},{"line_number":630,"context_line":"                change_queue.moveItem(item, nnfi)"},{"line_number":631,"context_line":"                changed \u003d True"},{"line_number":632,"context_line":"                self.cancelJobs(item)"},{"line_number":633,"context_line":"            if item.current_build_set.unable_to_merge:"},{"line_number":634,"context_line":"                failing_reasons.append(\"it has a merge conflict\")"},{"line_number":635,"context_line":"            if item.current_build_set.config_error:"}],"source_content_type":"text/x-python","patch_set":18,"id":"dfeb2761_9f0f4636","line":632,"updated":"2017-04-04 17:57:51.000000000","message":"I think I\u0027ve addressed the merge topic above.  The work division between prepareItem and prepareJobs you described is backward.  Performing a merge is *very* intensive.  It can take 30 seconds or longer for nova, for example (that is offloaded to a merge worker, of course, but we still have to take the hit of scheduling it and retrieving the results, and that will happen in a further iteration of the scheduler loop).  Calculating what jobs to run is a local data structure traversal which should take milliseconds at most.","commit_id":"e8c00539077906bbe9b7c647d7fa2efb3e2a90c8"},{"author":{"_account_id":6039,"name":"Joni Harker","email":"code@gentlydownthe.net","username":"jesusaurus"},"change_message_id":"8cf2e8296824f475096a36fd43175d48563be825","unresolved":false,"context_lines":[{"line_number":629,"context_line":"                              \"item, %s\" % (item.change, item_ahead, nnfi))"},{"line_number":630,"context_line":"                change_queue.moveItem(item, nnfi)"},{"line_number":631,"context_line":"                changed \u003d True"},{"line_number":632,"context_line":"                self.cancelJobs(item)"},{"line_number":633,"context_line":"            if item.current_build_set.unable_to_merge:"},{"line_number":634,"context_line":"                failing_reasons.append(\"it has a merge conflict\")"},{"line_number":635,"context_line":"            if item.current_build_set.config_error:"}],"source_content_type":"text/x-python","patch_set":18,"id":"dfeb2761_bf432a13","line":632,"updated":"2017-04-04 17:41:28.000000000","message":"The primary reason I want to schedule a merge job outside active window is to report merge conflicts without waiting through potentially long queue times. This is also why I split prepareLayout into prepareItem and prepareJobs, I was hoping prepareItem could be a bit more lightweight to limit the work outside the active window, and delay prepareJobs until inside the active window.","commit_id":"e8c00539077906bbe9b7c647d7fa2efb3e2a90c8"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"0f0453e774149ffdc8c848fdc3bebece961d5e9e","unresolved":false,"context_lines":[{"line_number":783,"context_line":"            item.setReportedResult(\u0027MERGER_FAILURE\u0027)"},{"line_number":784,"context_line":"        elif not item.getJobs():"},{"line_number":785,"context_line":"            # We don\u0027t send empty reports with +1,"},{"line_number":786,"context_line":"            # and the same for -1\u0027s (merge failures or transient errors)"},{"line_number":787,"context_line":"            # as they cannot be followed by +1\u0027s"},{"line_number":788,"context_line":"            self.log.debug(\"No jobs for change %s\" % item.change)"},{"line_number":789,"context_line":"            actions \u003d []"}],"source_content_type":"text/x-python","patch_set":18,"id":"dfeb2761_a4143f45","line":786,"updated":"2017-04-04 17:05:50.000000000","message":"-1: This comment is now wrong -- we will start sending -1s on merge failures for changes with no jobs (which is unavoidable since if we can\u0027t merge a change we don\u0027t get a list of jobs).","commit_id":"e8c00539077906bbe9b7c647d7fa2efb3e2a90c8"}]}
