mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-17 05:03:20 +00:00
141 lines
4.9 KiB
Python
141 lines
4.9 KiB
Python
import argparse
|
|
from datetime import timedelta, datetime
|
|
import logging
|
|
import os
|
|
from commit_status_helper import get_commit_filtered_statuses
|
|
from get_robot_token import get_best_robot_token
|
|
from github_helper import GitHub
|
|
from release import Release, Repo as ReleaseRepo, RELEASE_READY_STATUS
|
|
from report import SUCCESS
|
|
from ssh import SSHKey
|
|
|
|
LOGGER_NAME = __name__
|
|
HELPER_LOGGERS = ["github_helper", LOGGER_NAME]
|
|
logger = logging.getLogger(LOGGER_NAME)
|
|
|
|
|
|
def parse_args():
|
|
parser = argparse.ArgumentParser(
|
|
"Checks if enough days elapsed since the last release on each release "
|
|
"branches and do a release in case for green builds."
|
|
)
|
|
parser.add_argument("--token", help="GitHub token, if not set, used from smm")
|
|
parser.add_argument(
|
|
"--repo", default="ClickHouse/ClickHouse", help="Repo owner/name"
|
|
)
|
|
parser.add_argument("--dry-run", action="store_true", help="Do not create anything")
|
|
parser.add_argument(
|
|
"--release-after-days",
|
|
type=int,
|
|
default=3,
|
|
help="Do automatic release on the latest green commit after the latest "
|
|
"release if the newest release is older than the specified days",
|
|
)
|
|
parser.add_argument(
|
|
"--debug-helpers",
|
|
action="store_true",
|
|
help="Add debug logging for this script and github_helper",
|
|
)
|
|
parser.add_argument(
|
|
"--remote-protocol",
|
|
"-p",
|
|
default="ssh",
|
|
choices=ReleaseRepo.VALID,
|
|
help="repo protocol for git commands remote, 'origin' is a special case and "
|
|
"uses 'origin' as a remote",
|
|
)
|
|
|
|
return parser.parse_args()
|
|
|
|
|
|
def main():
|
|
args = parse_args()
|
|
logging.basicConfig(level=logging.INFO)
|
|
if args.debug_helpers:
|
|
for logger_name in HELPER_LOGGERS:
|
|
logging.getLogger(logger_name).setLevel(logging.DEBUG)
|
|
|
|
token = args.token or get_best_robot_token()
|
|
days_as_timedelta = timedelta(days=args.release_after_days)
|
|
now = datetime.now()
|
|
|
|
gh = GitHub(token)
|
|
prs = gh.get_release_pulls(args.repo)
|
|
branch_names = [pr.head.ref for pr in prs]
|
|
|
|
logger.info("Found release branches: %s\n ", " \n".join(branch_names))
|
|
repo = gh.get_repo(args.repo)
|
|
|
|
# In general there is no guarantee on which order the refs/commits are
|
|
# returned from the API, so we have to order them.
|
|
for pr in prs:
|
|
logger.info("Checking PR %s", pr.head.ref)
|
|
|
|
refs = list(repo.get_git_matching_refs(f"tags/v{pr.head.ref}"))
|
|
refs.sort(key=lambda ref: ref.ref)
|
|
|
|
latest_release_tag_ref = refs[-1]
|
|
latest_release_tag = repo.get_git_tag(latest_release_tag_ref.object.sha)
|
|
logger.info("That last release was done at %s", latest_release_tag.tagger.date)
|
|
|
|
if latest_release_tag.tagger.date + days_as_timedelta > now:
|
|
logger.info(
|
|
"Not enough days since the last release %s,"
|
|
" no automatic release can be done",
|
|
latest_release_tag.tag,
|
|
)
|
|
continue
|
|
|
|
unreleased_commits = list(
|
|
repo.get_commits(sha=pr.head.ref, since=latest_release_tag.tagger.date)
|
|
)
|
|
unreleased_commits.sort(
|
|
key=lambda commit: commit.commit.committer.date, reverse=True
|
|
)
|
|
|
|
for commit in unreleased_commits:
|
|
logger.info("Checking statuses of commit %s", commit.sha)
|
|
statuses = get_commit_filtered_statuses(commit)
|
|
all_success = all(st.state == SUCCESS for st in statuses)
|
|
passed_ready_for_release_check = any(
|
|
st.context == RELEASE_READY_STATUS and st.state == SUCCESS
|
|
for st in statuses
|
|
)
|
|
if not (all_success and passed_ready_for_release_check):
|
|
logger.info("Commit is not green, thus not suitable for release")
|
|
continue
|
|
|
|
logger.info("Commit is ready for release, let's release!")
|
|
|
|
release = Release(
|
|
ReleaseRepo(args.repo, args.remote_protocol),
|
|
commit.sha,
|
|
"patch",
|
|
args.dry_run,
|
|
True,
|
|
)
|
|
try:
|
|
release.do(True, True, True)
|
|
except:
|
|
if release.has_rollback:
|
|
logging.error(
|
|
"!!The release process finished with error, read the output carefully!!"
|
|
)
|
|
logging.error(
|
|
"Probably, rollback finished with error. "
|
|
"If you don't see any of the following commands in the output, "
|
|
"execute them manually:"
|
|
)
|
|
release.log_rollback()
|
|
raise
|
|
logging.info("New release is done!")
|
|
break
|
|
|
|
|
|
if __name__ == "__main__":
|
|
if os.getenv("ROBOT_CLICKHOUSE_SSH_KEY", ""):
|
|
with SSHKey("ROBOT_CLICKHOUSE_SSH_KEY"):
|
|
main()
|
|
else:
|
|
main()
|