ClickHouse/tests/ci/commit_status_helper.py

173 lines
5.0 KiB
Python
Raw Normal View History

2021-11-12 12:36:25 +00:00
#!/usr/bin/env python3
2022-03-18 12:36:45 +00:00
import csv
import os
import time
from typing import List, Literal
import logging
from github import Github
from github.Commit import Commit
from github.CommitStatus import CommitStatus
2023-02-22 16:00:06 +00:00
from ci_config import CI_CONFIG, REQUIRED_CHECKS
from env_helper import GITHUB_REPOSITORY, GITHUB_RUN_URL
2022-09-14 13:40:45 +00:00
from pr_info import PRInfo, SKIP_MERGEABLE_CHECK_LABEL
2021-11-26 14:00:09 +00:00
2021-12-28 10:13:51 +00:00
RETRY = 5
CommitStatuses = List[CommitStatus]
MERGEABLE_NAME = "Mergeable Check"
2021-12-28 10:13:51 +00:00
2022-11-10 16:11:23 +00:00
def override_status(status: str, check_name: str, invert: bool = False) -> str:
2022-03-10 16:39:18 +00:00
if CI_CONFIG["tests_config"].get(check_name, {}).get("force_tests", False):
2022-01-10 16:45:17 +00:00
return "success"
2022-03-10 16:39:18 +00:00
if invert:
if status == "success":
return "error"
return "success"
2022-03-10 16:39:18 +00:00
2022-01-10 16:45:17 +00:00
return status
2022-09-14 13:40:45 +00:00
def get_commit(gh: Github, commit_sha: str, retry_count: int = RETRY) -> Commit:
2021-12-28 10:13:51 +00:00
for i in range(retry_count):
try:
repo = gh.get_repo(GITHUB_REPOSITORY)
commit = repo.get_commit(commit_sha)
2022-09-14 13:40:45 +00:00
break
2021-12-28 10:13:51 +00:00
except Exception as ex:
if i == retry_count - 1:
raise ex
time.sleep(i)
2022-09-14 13:40:45 +00:00
return commit
2021-11-12 12:36:25 +00:00
2022-09-14 13:40:45 +00:00
def post_commit_status(
gh: Github, sha: str, check_name: str, description: str, state: str, report_url: str
2022-11-10 16:11:23 +00:00
) -> None:
2021-12-28 10:13:51 +00:00
for i in range(RETRY):
try:
commit = get_commit(gh, sha, 1)
2022-01-10 16:37:38 +00:00
commit.create_status(
context=check_name,
description=description,
state=state,
target_url=report_url,
)
2021-12-28 10:13:51 +00:00
break
except Exception as ex:
if i == RETRY - 1:
raise ex
time.sleep(i)
2022-03-18 12:36:45 +00:00
2022-09-14 13:40:45 +00:00
def post_commit_status_to_file(
file_path: str, description: str, state: str, report_url: str
2022-11-10 16:11:23 +00:00
) -> None:
2022-03-18 12:36:45 +00:00
if os.path.exists(file_path):
raise Exception(f'File "{file_path}" already exists!')
with open(file_path, "w", encoding="utf-8") as f:
out = csv.writer(f, delimiter="\t")
2022-03-18 12:36:45 +00:00
out.writerow([state, report_url, description])
2022-03-29 13:48:57 +00:00
2022-03-29 17:15:25 +00:00
def get_commit_filtered_statuses(commit: Commit) -> CommitStatuses:
"""
Squash statuses to latest state
1. context="first", state="success", update_time=1
2. context="second", state="success", update_time=2
3. context="first", stat="failure", update_time=3
=========>
1. context="second", state="success"
2. context="first", stat="failure"
"""
filtered = {}
for status in sorted(commit.get_statuses(), key=lambda x: x.updated_at):
filtered[status.context] = status
return list(filtered.values())
2022-11-10 16:11:23 +00:00
def remove_labels(gh: Github, pr_info: PRInfo, labels_names: List[str]) -> None:
2022-03-29 17:50:06 +00:00
repo = gh.get_repo(GITHUB_REPOSITORY)
pull_request = repo.get_pull(pr_info.number)
for label in labels_names:
pull_request.remove_from_labels(label)
2022-11-10 16:11:23 +00:00
def post_labels(gh: Github, pr_info: PRInfo, labels_names: List[str]) -> None:
2022-03-29 13:48:57 +00:00
repo = gh.get_repo(GITHUB_REPOSITORY)
pull_request = repo.get_pull(pr_info.number)
2022-03-29 17:28:18 +00:00
for label in labels_names:
pull_request.add_to_labels(label)
2022-07-19 12:57:03 +00:00
def format_description(description: str) -> str:
if len(description) > 140:
description = description[:137] + "..."
return description
def set_mergeable_check(
commit: Commit,
description: str = "",
state: Literal["success", "failure"] = "success",
) -> None:
commit.create_status(
context=MERGEABLE_NAME,
description=description,
state=state,
target_url=GITHUB_RUN_URL,
)
2022-11-10 16:11:23 +00:00
def update_mergeable_check(gh: Github, pr_info: PRInfo, check_name: str) -> None:
not_run = (
pr_info.labels.intersection({SKIP_MERGEABLE_CHECK_LABEL, "release"})
or check_name not in REQUIRED_CHECKS
or pr_info.release_pr
or pr_info.number == 0
)
if not_run:
# Let's avoid unnecessary work
return
logging.info("Update Mergeable Check by %s", check_name)
commit = get_commit(gh, pr_info.sha)
statuses = get_commit_filtered_statuses(commit)
required_checks = [
status for status in statuses if status.context in REQUIRED_CHECKS
]
mergeable_status = None
for status in statuses:
if status.context == MERGEABLE_NAME:
mergeable_status = status
break
success = []
fail = []
for status in required_checks:
if status.state == "success":
success.append(status.context)
else:
fail.append(status.context)
if fail:
description = "failed: " + ", ".join(fail)
if success:
description += "; succeeded: " + ", ".join(success)
description = format_description(description)
if mergeable_status is None or mergeable_status.description != description:
set_mergeable_check(commit, description, "failure")
return
description = ", ".join(success)
description = format_description(description)
if mergeable_status is None or mergeable_status.description != description:
set_mergeable_check(commit, description)