def handle()

in mozci/console/commands/check_backfills.py [0:0]


    def handle(self) -> None:
        branch = self.option("branch")
        environment = self.option("environment")
        matrix_room = config.get("matrix-room-id")
        current_task_id = os.environ.get("TASK_ID")

        try:
            nb_pushes = int(self.option("nb-pushes"))
        except ValueError:
            self.line("<error>Provided --nb-pushes should be an int.</error>")
            exit(1)

        self.line("<comment>Loading pushes...</comment>")
        self.pushes = make_push_objects(nb=nb_pushes, branch=branch)
        nb_pushes = len(self.pushes)

        to_notify: Dict[str, Dict[str, Any]] = {}
        for index, push in enumerate(self.pushes, start=1):
            self.line(
                f"<comment>Processing push {index}/{nb_pushes}: {push.push_uuid}</comment>"
            )
            backfill_tasks = []

            try:
                indexed_tasks = list_indexed_tasks(
                    f"gecko.v2.{push.branch}.revision.{push.rev}.taskgraph.actions"
                )
            except requests.exceptions.HTTPError as e:
                self.line(
                    f"<error>Couldn't fetch indexed tasks on push {push.push_uuid}: {e}</error>"
                )
                continue

            for indexed_task in indexed_tasks:
                task_id = indexed_task["taskId"]
                try:
                    children_tasks = list_dependent_tasks(task_id)
                except requests.exceptions.HTTPError as e:
                    self.line(
                        f"<error>Couldn't fetch dependent tasks of indexed task {task_id} on push {push.push_uuid}: {e}</error>"
                    )
                    continue

                for child_task in children_tasks:
                    task_section = child_task.get("task", {})
                    task_action = task_section.get("tags", {}).get("action", "")
                    # We are looking for the Treeherder symbol because Sheriffs are
                    # only interested in backfill-tasks holding the '-bk' suffix in TH
                    th_symbol = (
                        task_section.get("extra", {})
                        .get("treeherder", {})
                        .get("symbol", "")
                    )
                    status = child_task.get("status", {})
                    if task_action == "backfill-task" and th_symbol.endswith("-bk"):
                        assert status.get(
                            "taskId"
                        ), "Missing taskId attribute in backfill task status"
                        label = task_section.get("tags", {}).get(
                            "label"
                        ) or task_section.get("metadata", {}).get("name")
                        assert (
                            label
                        ), "Missing label attribute in backfill task tags or name attribute in backfill task metadata"
                        assert status.get(
                            "state"
                        ), "Missing state attribute in backfill task status"
                        backfill_tasks.append(
                            BackfillTask(
                                status["taskId"], label, th_symbol, status["state"]
                            )
                        )
                    else:
                        logger.debug(
                            f"Skipping non-backfill task {status.get('taskId')}"
                        )

            def group_key(task):
                return task.th_symbol

            # Sorting backfill tasks by their Treeherder symbol
            backfill_tasks = sorted(backfill_tasks, key=group_key)
            # Grouping ordered backfill tasks by their associated Treeherder symbol
            for th_symbol, tasks_iter in groupby(backfill_tasks, group_key):
                if th_symbol not in to_notify:
                    to_notify[th_symbol] = {
                        "newest_push": None,
                        "backfill_tasks": set(),
                    }

                # make_push_objects returns the latest pushes in chronological order from oldest to newest
                # We only need to store the newest Push that appeared for this Treeherder symbol
                to_notify[th_symbol]["newest_push"] = push
                # Storing all backfill tasks for this symbol across multiple pushes
                to_notify[th_symbol]["backfill_tasks"].update(tasks_iter)

        for th_symbol, data in to_notify.items():
            logger.debug("Preparing notification for the Treeherder symbol {th_symbol}")

            all_backfill_tasks = data["backfill_tasks"]
            # Checking that all backfill tasks for this symbol are in a "final" state
            if not all(task.state in TASK_FINAL_STATES for task in all_backfill_tasks):
                logger.debug(
                    f"Not all backfill tasks for the Treeherder symbol {th_symbol} are in a final state, not notifying now."
                )
                continue

            newest_push = data["newest_push"]
            index_path = f"project.mozci.check-backfill.{environment}.{newest_push.branch}.{newest_push.rev}.{th_symbol}"
            try:
                find_task_id(index_path, root_url=COMMUNITY_TASKCLUSTER_ROOT_URL)
            except requests.exceptions.HTTPError:
                pass
            else:
                logger.debug(
                    f"A notification was already sent for the backfill tasks associated to the Treeherder symbol {th_symbol}."
                )
                continue

            try:
                parents = [
                    parent for parent in newest_push._iterate_parents(max_depth=20)
                ]
            except Exception as e:
                logger.debug(
                    f"Failed to load the last twenty parent pushes for push {newest_push.push_uuid}, because: {e}."
                )
                parents = None

            logger.debug("Generating notification text")

            cleaned_label = re.sub(
                r"(-e10s|-1proc)?(-\d+)?$", "", all_backfill_tasks.pop().label
            )
            notification = NOTIFICATION_BACKFILL_GROUP_COMPLETED.format(
                th_symbol=th_symbol,
                push=newest_push,
                tochange=f"&tochange={newest_push.child.rev}",
                fromchange=f"&fromchange={parents[-1].rev}" if parents else "",
                searchstr=f"&searchStr={cleaned_label}",
            )

            if not matrix_room:
                self.line(
                    f"<comment>A notification should be sent for the backfill tasks associated to the Treeherder symbol {th_symbol} but no matrix room was provided in the secret.</comment>"
                )
                logger.debug(f"The notification: {notification}")
                continue

            logger.debug("Sending Matrix notification")

            # Sending a notification to the Matrix channel defined in secret
            notify_matrix(
                room=matrix_room,
                body=notification,
            )

            if not current_task_id:
                self.line(
                    f"<comment>The current task should be indexed in {index_path} but TASK_ID environment variable isn't set.</comment>"
                )
                continue

            logger.debug("Indexing current task")

            # Populating the index with the current task to prevent sending the notification once again
            index_current_task(
                index_path,
                root_url=COMMUNITY_TASKCLUSTER_ROOT_URL,
            )