mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-10 09:32:06 +00:00
175 lines
5.0 KiB
Python
175 lines
5.0 KiB
Python
#!/usr/bin/env python3
|
|
|
|
import csv
|
|
import os
|
|
import time
|
|
from typing import List, Literal
|
|
import logging
|
|
|
|
from ci_config import CI_CONFIG, REQUIRED_CHECKS
|
|
from env_helper import GITHUB_REPOSITORY, GITHUB_RUN_URL
|
|
from github import Github
|
|
from github.Commit import Commit
|
|
from github.CommitStatus import CommitStatus
|
|
from pr_info import PRInfo, SKIP_MERGEABLE_CHECK_LABEL
|
|
|
|
RETRY = 5
|
|
CommitStatuses = List[CommitStatus]
|
|
MERGEABLE_NAME = "Mergeable Check"
|
|
|
|
|
|
def override_status(status: str, check_name: str, invert: bool = False) -> str:
|
|
if CI_CONFIG["tests_config"].get(check_name, {}).get("force_tests", False):
|
|
return "success"
|
|
|
|
if invert:
|
|
if status == "success":
|
|
return "error"
|
|
return "success"
|
|
|
|
return status
|
|
|
|
|
|
def get_commit(gh: Github, commit_sha: str, retry_count: int = RETRY) -> Commit:
|
|
for i in range(retry_count):
|
|
try:
|
|
repo = gh.get_repo(GITHUB_REPOSITORY)
|
|
commit = repo.get_commit(commit_sha)
|
|
break
|
|
except Exception as ex:
|
|
if i == retry_count - 1:
|
|
raise ex
|
|
time.sleep(i)
|
|
|
|
return commit
|
|
|
|
|
|
def post_commit_status(
|
|
gh: Github, sha: str, check_name: str, description: str, state: str, report_url: str
|
|
) -> None:
|
|
for i in range(RETRY):
|
|
try:
|
|
commit = get_commit(gh, sha, 1)
|
|
commit.create_status(
|
|
context=check_name,
|
|
description=description,
|
|
state=state,
|
|
target_url=report_url,
|
|
)
|
|
break
|
|
except Exception as ex:
|
|
if i == RETRY - 1:
|
|
raise ex
|
|
time.sleep(i)
|
|
|
|
|
|
def post_commit_status_to_file(
|
|
file_path: str, description: str, state: str, report_url: str
|
|
) -> None:
|
|
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")
|
|
out.writerow([state, report_url, description])
|
|
|
|
|
|
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())
|
|
|
|
|
|
def remove_labels(gh: Github, pr_info: PRInfo, labels_names: List[str]) -> None:
|
|
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)
|
|
|
|
|
|
def post_labels(gh: Github, pr_info: PRInfo, labels_names: List[str]) -> None:
|
|
repo = gh.get_repo(GITHUB_REPOSITORY)
|
|
pull_request = repo.get_pull(pr_info.number)
|
|
for label in labels_names:
|
|
pull_request.add_to_labels(label)
|
|
|
|
|
|
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,
|
|
)
|
|
|
|
|
|
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 not None and mergeable_status.description == description:
|
|
return
|
|
set_mergeable_check(commit, description, "failure")
|
|
return
|
|
|
|
description = ", ".join(success)
|
|
description = format_description(description)
|
|
if mergeable_status is not None and mergeable_status.description == description:
|
|
return
|
|
|
|
set_mergeable_check(commit, description)
|