def follow_dup()

in libmozdata/bugzilla.py [0:0]


    def follow_dup(bugids, only_final=True):
        """Follow the duplicated bugs

        Args:
            bugids (List[str]): list of bug ids
            only_final (bool): if True only the final bug is returned else all the chain

        Returns:
            dict: each bug in entry is mapped to the last bug in the duplicate chain (None if there's no dup and 'cycle' if a cycle is detected)
        """
        include_fields = ["id", "resolution", "dupe_of"]
        dup = {}
        _set = set()
        for bugid in bugids:
            dup[str(bugid)] = None

        def bughandler(bug):
            if bug["resolution"] == "DUPLICATE":
                dupeofid = str(bug["dupe_of"])
                dup[str(bug["id"])] = [dupeofid]
                _set.add(dupeofid)

        bz = Bugzilla(
            bugids=bugids, include_fields=include_fields, bughandler=bughandler
        ).get_data()
        bz.wait_bugs()

        def bughandler2(bug):
            if bug["resolution"] == "DUPLICATE":
                bugid = str(bug["id"])
                for _id, dupid in dup.items():
                    if dupid and dupid[-1] == bugid:
                        dupeofid = str(bug["dupe_of"])
                        if dupeofid == _id or dupeofid in dupid:
                            # avoid infinite loop if any
                            dup[_id].append("cycle")
                        else:
                            dup[_id].append(dupeofid)
                            _set.add(dupeofid)

        bz.bughandler = Handler(bughandler2)

        while _set:
            bz.bugids = list(_set)
            _set.clear()
            bz.got_data = False
            bz.get_data().wait_bugs()

        if only_final:
            for k, v in dup.items():
                dup[k] = v[-1] if v else None

        return dup