Repository: ClickHouse/ClickHouse
File: tests/ci/cherry_pick.py (Python)

Code before:
            self.cherrypick_pr.create_issue_comment(comment_body)
            self.cherrypick_pr.edit(state="closed")
            return

        # Ping after 3 days
        # Check if we've already pinged to avoid spamming
        comments = self.cherrypick_pr.get_issue_comments()
        for comment in comments:
            if (
                "has not been updated for" in comment.body
                and "resolve the conflicts" in comment.body
            ):
                # We've already pinged, don't ping again
                logging.info(
                    "Already pinged cherry-pick PR #%s, waiting for update or closure threshold",
                    self.cherrypick_pr.number,
                )
                return

        assignees = ", ".join(f"@{user.login}" for user in self.cherrypick_pr.assignees)
        comment_body = (
            f"Dear {assignees}, this cherry-pick PR has not been updated for {since_updated_str}. "
            f"Please resolve the conflicts to backport #{self.pr.number}, "
            "or close this PR if the backport is no longer needed. "
            f"This PR will be automatically closed after {CLOSE_THRESHOLD // 86400} days of inactivity."
        )
        if dry_run:
            logging.info(
                "DRY RUN: would comment on cherry-pick PR #%s:\n%s",
                self.cherrypick_pr.number,
                comment_body,
            )
            return

        self.cherrypick_pr.create_issue_comment(comment_body)

    def _assign_new_pr(self, new_pr: PullRequest) -> None:
        """Assign `new_pr` to author, merger and assignees of an original PR"""
        # It looks there some race when multiple .add_to_assignees are executed,
        # so we'll add all at once
        assignees = [self.pr.user, self.pr.merged_by]
        if self.pr.assignees:
            assignees.extend(self.pr.assignees)
        assignees = [
            a
            for a in assignees
            if "robot-clickhouse" not in str(a) and "clickhouse-gh" not in str(a)
        ]
        logging.info(
            "Assing #%s to author and assignees of the original PR: %s",
            new_pr.number,

Review comment (bug):
If `self.cherrypick_pr.assignees` is empty (e.g., manual unassign, assignment API failure, permission issues), the bot will post `Dear , ...` and won’t actually notify anyone. Consider handling the empty case explicitly (e.g., assign at least one fallback reviewer/author before commenting, or omit the greeting and include another notification mechanism).

Code after:
                    f"This cherry-pick PR has not been updated for {since_updated_str}. "
                    f"Closing automatically. If you still want to backport #{self.pr.number}, "
                    "please resolve the conflicts and reopen this PR."
                )
            if dry_run:
                logging.info(
                    "DRY RUN: would close cherry-pick PR #%s with comment:\n%s",
                    self.cherrypick_pr.number,
                    comment_body,
                )
                return
            self.cherrypick_pr.create_issue_comment(comment_body)
            logging.info(
                "Posted closing comment to cherry-pick PR #%s",
                self.cherrypick_pr.number,
            )
            self.cherrypick_pr.edit(state="closed")
            logging.info(
                "Closed cherry-pick PR #%s after %s of inactivity",
                self.cherrypick_pr.number,
                since_updated_str,
            )
            return

        # Ping after 3 days
        # Check if we've already pinged to avoid spamming
        comments = self.cherrypick_pr.get_issue_comments()
        for comment in comments:
            if (
                "has not been updated for" in comment.body
                and "resolve the conflicts" in comment.body
            ):
                # We've already pinged, don't ping again
                logging.info(
                    "Already pinged cherry-pick PR #%s, waiting for update or closure threshold",
                    self.cherrypick_pr.number,
                )
                return

        if self.cherrypick_pr.assignees:
            assignees = ", ".join(
                f"@{user.login}" for user in self.cherrypick_pr.assignees
            )
            comment_body = (
                f"Dear {assignees}, this cherry-pick PR has not been updated for {since_updated_str}. "
                f"Please resolve the conflicts to backport #{self.pr.number}, "
                "or close this PR if the backport is no longer needed. "
                f"This PR will be automatically closed after {CLOSE_THRESHOLD // 86400} days of inactivity."
            )
        else:
            logging.warning(