def test_auto_merge_branches_subscribed(self):
     """Auto merging is triggered by ScanCompleted."""
     source = self.factory.makeBranch()
     source.last_scanned_id = '23foo'
     target = self.factory.makeBranchTargetBranch(source.target)
     target.product.development_focus.branch = target
     logger = logging.getLogger('test')
     notify(events.ScanCompleted(target, None, logger, ['23foo']))
     self.assertEqual(BranchLifecycleStatus.MERGED, source.lifecycle_status)
Beispiel #2
0
 def autoMergeBranches(self, db_branch, new_ancestry):
     mergedetection.auto_merge_branches(
         events.ScanCompleted(
             db_branch=db_branch, bzr_branch=None,
             logger=None, new_ancestry=new_ancestry))
Beispiel #3
0
    def syncBranch(self, bzr_branch):
        """Synchronize the database view of a branch with Bazaar data.

        `bzr_branch` must be read locked.

        Several tables must be updated:

        * Revision: there must be one Revision row for each revision in the
          branch ancestry. If the row for a revision that has just been added
          to the branch is already present, it must be checked for
          consistency.

        * BranchRevision: there must be one BrancheRevision row for each
          revision in the branch ancestry. If history revisions became merged
          revisions, the corresponding rows must be changed.

        * Branch: the branch-scanner status information must be updated when
          the sync is complete.
        """
        self.logger.info("Scanning branch: %s", self.db_branch.unique_name)
        self.logger.info("    from %s", bzr_branch.base)
        # Get the history and ancestry from the branch first, to fail early
        # if something is wrong with the branch.
        self.logger.info("Retrieving history from bzrlib.")
        bzr_history = branch_revision_history(bzr_branch)
        # The BranchRevision, Revision and RevisionParent tables are only
        # written to by the branch-scanner, so they are not subject to
        # write-lock contention. Update them all in a single transaction to
        # improve the performance and allow garbage collection in the future.
        db_ancestry, db_history = self.retrieveDatabaseAncestry()

        (new_ancestry, branchrevisions_to_delete,
         revids_to_insert) = self.planDatabaseChanges(bzr_branch, bzr_history,
                                                      db_ancestry, db_history)
        new_db_revs = (new_ancestry -
                       getUtility(IRevisionSet).onlyPresent(new_ancestry))
        self.logger.info("Adding %s new revisions.", len(new_db_revs))
        for revids in iter_list_chunks(list(new_db_revs), 10000):
            revisions = self.getBazaarRevisions(bzr_branch, revids)
            self.syncRevisions(bzr_branch, revisions, revids_to_insert)
        self.deleteBranchRevisions(branchrevisions_to_delete)
        self.insertBranchRevisions(bzr_branch, revids_to_insert)
        transaction.commit()
        # Synchronize the RevisionCache for this branch.
        getUtility(IRevisionSet).updateRevisionCacheForBranch(self.db_branch)
        transaction.commit()

        # Notify any listeners that the tip of the branch has changed, but
        # before we've actually updated the database branch.
        initial_scan = (len(db_history) == 0)
        notify(events.TipChanged(self.db_branch, bzr_branch, initial_scan))

        # The Branch table is modified by other systems, including the web UI,
        # so we need to update it in a short transaction to avoid causing
        # timeouts in the webapp. This opens a small race window where the
        # revision data is updated in the database, but the Branch table has
        # not been updated. Since this has no ill-effect, and can only err on
        # the pessimistic side (tell the user the data has not yet been
        # updated although it has), the race is acceptable.
        self.updateBranchStatus(bzr_history)
        notify(
            events.ScanCompleted(self.db_branch, bzr_branch, self.logger,
                                 new_ancestry))
        transaction.commit()