diff --git a/.github/scripts/delete_old_branches.py b/.github/scripts/delete_old_branches.py index b96c3956856f..8032008edf12 100644 --- a/.github/scripts/delete_old_branches.py +++ b/.github/scripts/delete_old_branches.py @@ -275,7 +275,7 @@ def delete_branches() -> None: delete_branch(git_repo, branch) -def delete_old_ciflow_tags() -> None: +def delete_old_tags() -> None: # Deletes ciflow tags if they are associated with a closed PR or a specific # commit. Lightweight tags don't have information about the date they were # created, so we can't check how old they are. The script just assumes that @@ -288,23 +288,29 @@ def delete_old_ciflow_tags() -> None: delete_branch(git_repo, f"refs/tags/{tag}") tags = git_repo._run_git("tag").splitlines() - open_pr_numbers = [x["number"] for x in get_open_prs()] + CIFLOW_TAG_REGEX = re.compile(r"^ciflow\/.*\/(\d{5,6}|[0-9a-f]{40})$") + AUTO_REVERT_TAG_REGEX = re.compile(r"^trunk\/[0-9a-f]{40}$") for tag in tags: try: if ESTIMATED_TOKENS[0] > 400: print("Estimated tokens exceeded, exiting") break - if not tag.startswith("ciflow/"): + + if not CIFLOW_TAG_REGEX.match(tag) and not AUTO_REVERT_TAG_REGEX.match(tag): continue - re_match_pr = re.match(r"^ciflow\/.*\/(\d{5,6})$", tag) - re_match_sha = re.match(r"^ciflow\/.*\/([0-9a-f]{40})$", tag) - if re_match_pr: - pr_number = int(re_match_pr.group(1)) - if pr_number in open_pr_numbers: - continue - delete_tag(tag) - elif re_match_sha: + + # This checks the date of the commit associated with the tag instead + # of the tag itself since lightweight tags don't have this + # information. I think it should be ok since this only runs once a + # day + tag_info = git_repo._run_git("show", "-s", "--format=%ct", tag) + tag_timestamp = int(tag_info.strip()) + # Maybe some timezone issues, but a few hours shouldn't matter + tag_age_days = (datetime.now().timestamp() - tag_timestamp) / SEC_IN_DAY + + if tag_age_days > 7: + print(f"[{tag}] Tag is older than 7 days, deleting") delete_tag(tag) except Exception as e: print(f"Failed to check tag {tag}: {e}") @@ -312,4 +318,4 @@ def delete_old_ciflow_tags() -> None: if __name__ == "__main__": delete_branches() - delete_old_ciflow_tags() + delete_old_tags() diff --git a/.github/scripts/test_delete_old_branches.py b/.github/scripts/test_delete_old_branches.py new file mode 100644 index 000000000000..08ccd84f7d29 --- /dev/null +++ b/.github/scripts/test_delete_old_branches.py @@ -0,0 +1,56 @@ +import os +import unittest +from datetime import datetime +from unittest.mock import MagicMock, patch + + +os.environ["GITHUB_TOKEN"] = "test_token" + +from delete_old_branches import delete_old_tags + + +@patch("delete_old_branches.delete_branch") +@patch("gitutils.GitRepo._run_git") +class TestDeleteTag(unittest.TestCase): + def test_delete_tag( + self, mock_run_git: "MagicMock", mock_delete_tag: "MagicMock" + ) -> None: + for tag in [ + "ciflow/branch/12345", + "ciflow/commitsha/1234567890abcdef1234567890abcdef12345678", + "trunk/1234567890abcdef1234567890abcdef12345678", + ]: + mock_run_git.side_effect = [ + tag, + str(int(datetime.now().timestamp() - 8 * 24 * 60 * 60)), # 8 days ago + ] + delete_old_tags() + mock_delete_tag.assert_called_once() + mock_delete_tag.reset_mock() + + # Don't delete if the tag is not old enough + mock_run_git.side_effect = [ + tag, + str(int(datetime.now().timestamp() - 6 * 24 * 60 * 60)), # 6 days ago + ] + delete_old_tags() + mock_delete_tag.assert_not_called() + + def test_do_not_delete_tag( + self, mock_run_git: "MagicMock", mock_delete_tag: "MagicMock" + ) -> None: + for tag in [ + "ciflow/doesntseemtomatch", + "trunk/doesntseemtomatch", + "doesntseemtomatch", + ]: + mock_run_git.side_effect = [ + tag, + str(int(datetime.now().timestamp() - 8 * 24 * 60 * 60)), # 8 days ago + ] + delete_old_tags() + mock_delete_tag.assert_not_called() + + +if __name__ == "__main__": + unittest.main()