#!/usr/bin/env python3 import datetime import glob import os import re import sys import requests import semver def release(): major_version = 4 gitlab_project_id = os.environ["CI_PROJECT_ID"] api_token = os.environ["CISCRIPT_API_TOKEN"] minor_version = os.environ["MINOR_VERSION"] if minor_version == "minor": minor_version = None else: try: minor_version = int(minor_version) except ValueError: sys.exit(f"minor version must be number but is '{minor_version}'") patch_version = os.environ["PATCH_VERSION"] if patch_version == "patch": patch_version = None else: try: patch_version = int(patch_version) except ValueError: sys.exit(f"patch version must be number but is '{patch_version}'") branch = os.environ["CI_COMMIT_BRANCH"] print(f"branch '{branch}'") if branch == "master": if minor_version is None: sys.exit("minor version must be set") if patch_version is None: patch_version = 0 future_version = f"{major_version}.{minor_version}.{patch_version}" response = requests.get( ( f"https://gitlab.princip.cz/" f"api/v4/projects/{gitlab_project_id}/repository/tags" ), headers={"PRIVATE-TOKEN": api_token}, params={"search": "^v"}, ) for tag_dict in response.json(): tag_name = tag_dict["name"] if (re.match(r"^v\d+\.\d+\.\d+$", tag_name) and semver.compare(future_version, tag_name[1:]) < 1): sys.exit( f"existing version '{tag_name[1:]}' " f"is greater than or equal to future version " f"'{future_version}'" ) elif match := re.match(r"^stable-(\d+)\.(\d+)$", branch): if patch_version is None: sys.exit("patch version must be set") major_version = int(match.group(1)) branch_minor_version = int(match.group(2)) if minor_version is None: minor_version = branch_minor_version elif minor_version != branch_minor_version: sys.exit( f"minor version on branch '{branch}' " f"must be '{branch_minor_version}' or blank (default)" ) future_version = f"{major_version}.{minor_version}.{patch_version}" response = requests.get( ( f"https://gitlab.princip.cz/" f"api/v4/projects/{gitlab_project_id}/repository/tags" ), headers={"PRIVATE-TOKEN": api_token}, params={"search": f"^v{major_version}.{minor_version}"}, ) for tag_dict in response.json(): tag_name = tag_dict["name"] if semver.compare(future_version, tag_name[1:]) < 1: sys.exit( f"existing version '{tag_name[1:]}' " f"is greater than or equal to future version " f"'{future_version}'" ) else: sys.exit(f"release on branch '{branch}' is forbidden") print(f"future version '{future_version}'") future_tag_name = f"v{future_version}" print(f"future tag name '{future_tag_name}'") response = requests.get( ( f"https://gitlab.princip.cz/" f"api/v4/projects/{gitlab_project_id}/repository/tags" f"/{future_tag_name}" ), headers={"PRIVATE-TOKEN": api_token}, ) if response.status_code != 404: sys.exit(f"tag '{future_tag_name}' already exists") commit_message = f"update files for {future_version}" payload_dict = { "branch": branch, "commit_message": commit_message, "actions": []} today_date = datetime.datetime.today().strftime("%Y-%m-%d") release_description = f"## {future_version} ({today_date})\n" change_file_fps = glob.glob(os.path.join("incoming_changes", "*.md")) if not change_file_fps: sys.exit("no change file") for change_file_fp in change_file_fps: change_file_fn = os.path.basename(change_file_fp) match = re.match(r"^(\d+)-\S+.md$", change_file_fn) if match: issue_no = match.group(1) else: issue_no = None with open(change_file_fp, "r") as change_file: for line in change_file: line = line.strip() if issue_no: line += f" #{issue_no}" release_description += f"{line}\n" payload_dict["actions"].append( {"action": "delete", "file_path": change_file_fp}) with open("CHANGELOG.md", "r+") as changelog_file: content = changelog_file.read() new_changelog_content = f"{release_description}\n\n{content}" payload_dict["actions"].append({ "action": "update", "file_path": "CHANGELOG.md", "content": new_changelog_content, }) print("CHANGELOG.md updated") response = requests.post( ( f"https://gitlab.princip.cz/" f"api/v4/projects/{gitlab_project_id}/repository/commits" ), headers={"PRIVATE-TOKEN": api_token}, json=payload_dict, ) if response.status_code == 201: print(f"commit '{commit_message}' created") else: sys.exit( f"error creating commit '{commit_message}', " f"status code '{response.status_code}', json '{response.json()}'" ) response = requests.post( ( f"https://gitlab.princip.cz/" f"api/v4/projects/{gitlab_project_id}/repository/tags" ), headers={"PRIVATE-TOKEN": api_token}, params={"tag_name": future_tag_name, "ref": branch}, ) if response.status_code == 201: print(f"tag '{future_tag_name}' created") else: sys.exit( f"error creating tag '{future_tag_name}', " f"status code '{response.status_code}', " f"json '{response.json()}'" ) if __name__ == "__main__": release()