From cb141bcb55f2bcf14136b57eb086acfbd41adc74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Brunner?= Date: Wed, 28 Jul 2021 10:37:16 +0200 Subject: [PATCH] Add deployment of Helm charts --- Makefile | 4 + c2cciutils/__init__.py | 7 +- c2cciutils/configuration.py | 452 +++++++++++++++++++++++++--------- c2cciutils/publish.py | 63 +++++ c2cciutils/schema.json | 31 +++ c2cciutils/scripts/publish.py | 128 +++++++--- jsonschema-gentypes.yaml | 2 - test/helmchart/Chart.yaml | 5 + 8 files changed, 541 insertions(+), 151 deletions(-) create mode 100644 test/helmchart/Chart.yaml diff --git a/Makefile b/Makefile index 478252d60..bfb360eef 100644 --- a/Makefile +++ b/Makefile @@ -14,3 +14,7 @@ checks: prospector .PHONY: prospector prospector: build-checker docker run --volume=${PWD}:/app $(GITHUB_REPOSITORY)-checker prospector --ignore-paths=example-project/ --output=pylint + +.PHONY: jsonschema +jsonschema: + jsonschema-gentypes diff --git a/c2cciutils/__init__.py b/c2cciutils/__init__.py index 71cbb55b0..6fa7aaaa4 100644 --- a/c2cciutils/__init__.py +++ b/c2cciutils/__init__.py @@ -2,6 +2,7 @@ c2cciutils shared utils function. """ +import glob import json import os.path import pkgutil @@ -10,12 +11,12 @@ import sys from typing import Any, Dict, List, Match, Optional, Pattern, Tuple, TypedDict, cast -import jsonschema_gentypes.validate import magic import requests import ruamel.yaml import c2cciutils.configuration +import jsonschema_gentypes.validate def get_repository() -> str: @@ -151,6 +152,10 @@ def get_config() -> c2cciutils.configuration.Configuration: "dockerhub": {"versions": ["version_tag", "version_branch", "rebuild", "feature_branch"]}, }, }, + "helm": { + "versions": ["version_tag"], + "folders": [os.path.dirname(f) for f in glob.glob("./**/Chart.yaml", recursive=True)], + }, "publish": {"google_calendar": {"on": ["version_branch", "version_tag", "rebuild"]}}, }, "checks": { diff --git a/c2cciutils/configuration.py b/c2cciutils/configuration.py index c56976d3a..a9c07a578 100644 --- a/c2cciutils/configuration.py +++ b/c2cciutils/configuration.py @@ -3,20 +3,26 @@ """ -from typing import List, Any, Literal, Dict, TypedDict, Union - +from typing import Any, Dict, List, Literal, TypedDict, Union # Audit # # The audit configuration -class Audit(TypedDict, total=False): - npm: "AuditNpm" - outdated_versions: "AuditOutdatedVersions" - pip: "AuditPip" - pipenv: "AuditPipenv" - pipfile: "AuditPipfile" - pipfile_lock: "AuditPipfileLock" - print_versions: "PrintVersions" +Audit = TypedDict( + "Audit", + { + "npm": "AuditNpm", + "outdated_versions": "AuditOutdatedVersions", + "pip": "AuditPip", + "pipenv": "AuditPipenv", + "pipfile": "AuditPipfile", + "pipfile_lock": "AuditPipfileLock", + # WARNING: The required are not correctly taken in account, + # See: https://github.com/camptocamp/jsonschema-gentypes/issues/6 + "print_versions": "PrintVersions", + }, + total=False, +) # audit npm @@ -30,8 +36,14 @@ class Audit(TypedDict, total=False): # audit npm config # # The npm audit configuration -class AuditNpmConfig(TypedDict, total=False): - cwe_ignore: List[str] +AuditNpmConfig = TypedDict( + "AuditNpmConfig", + { + # The list of CWE id to be ignored + "cwe_ignore": List[str], + }, + total=False, +) # Audit outdated versions @@ -57,8 +69,13 @@ class AuditNpmConfig(TypedDict, total=False): # Audit pipenv config # # The audit Pipfile and Pipfile.lock configuration (old version) -class AuditPipenvConfig(TypedDict, total=False): - python_versions: List[str] +AuditPipenvConfig = TypedDict( + "AuditPipenvConfig", + { + "python_versions": List[str], + }, + total=False, +) # Audit pipfile @@ -72,8 +89,14 @@ class AuditPipenvConfig(TypedDict, total=False): # Audit pipfile config # # The audit Pipfile configuration -class AuditPipfileConfig(TypedDict, total=False): - sections: List[str] +AuditPipfileConfig = TypedDict( + "AuditPipfileConfig", + { + # The section to be audited + "sections": List[str], + }, + total=False, +) # Audit pipfile lock @@ -87,29 +110,42 @@ class AuditPipfileConfig(TypedDict, total=False): # Audit pipfile lock config # # The audit Pipfile.lock configuration -class AuditPipfileLockConfig(TypedDict, total=False): - sections: List[str] +AuditPipfileLockConfig = TypedDict( + "AuditPipfileLockConfig", + { + # The section to be audited + "sections": List[str], + }, + total=False, +) # Checks # # The checkers configurations -class Checks(TypedDict, total=False): - black: "ChecksBlack" - black_config: "ChecksBlackConfiguration" - codespell: "ChecksCodespell" - dependabot_config: "ChecksDependabotConfiguration" - editorconfig: "ChecksEditorconfig" - eof: "ChecksEof" - gitattribute: "ChecksGitattribute" - isort: "ChecksIsort" - print_config: "ChecksPrintConfig" - required_workflows: "ChecksRequiredWorkflows" - versions: "ChecksVersions" - workflows: "ChecksWorkflows" - setup: "ChecksSetup" - prettier: "ChecksPrettier" - print_versions: "PrintVersions" +Checks = TypedDict( + "Checks", + { + "black": "ChecksBlack", + "black_config": "ChecksBlackConfiguration", + "codespell": "ChecksCodespell", + "dependabot_config": "ChecksDependabotConfiguration", + "editorconfig": "ChecksEditorconfig", + "eof": "ChecksEof", + "gitattribute": "ChecksGitattribute", + "isort": "ChecksIsort", + "print_config": "ChecksPrintConfig", + "required_workflows": "ChecksRequiredWorkflows", + "versions": "ChecksVersions", + "workflows": "ChecksWorkflows", + "setup": "ChecksSetup", + "prettier": "ChecksPrettier", + # WARNING: The required are not correctly taken in account, + # See: https://github.com/camptocamp/jsonschema-gentypes/issues/6 + "print_versions": "PrintVersions", + }, + total=False, +) # Checks Black @@ -123,9 +159,15 @@ class Checks(TypedDict, total=False): # Checks black config # # The Black check configuration -class ChecksBlackConfig(TypedDict, total=False): - properties: Dict[str, Any] - ignore_patterns_re: List[str] +ChecksBlackConfig = TypedDict( + "ChecksBlackConfig", + { + "properties": Dict[str, Any], + # List of regular expression that should be ignored + "ignore_patterns_re": List[str], + }, + total=False, +) # Checks Black configuration @@ -139,8 +181,14 @@ class ChecksBlackConfig(TypedDict, total=False): # Checks black configuration config # # The Black configuration check configuration -class ChecksBlackConfigurationConfig(TypedDict, total=False): - properties: Dict[str, Union[Union[int, float], str]] +ChecksBlackConfigurationConfig = TypedDict( + "ChecksBlackConfigurationConfig", + { + # The properties key = value thet should be present + "properties": Dict[str, Union[Union[int, float], str]], + }, + total=False, +) # Checks codespell @@ -154,9 +202,16 @@ class ChecksBlackConfigurationConfig(TypedDict, total=False): # Checks codespell config # # The codespell check configuration -class ChecksCodespellConfig(TypedDict, total=False): - arguments: List[str] - ignore_re: List[str] +ChecksCodespellConfig = TypedDict( + "ChecksCodespellConfig", + { + # List of argument that will be added to the codspell command + "arguments": List[str], + # List of regular expression that should be ignored + "ignore_re": List[str], + }, + total=False, +) # Checks Dependabot configuration @@ -170,10 +225,18 @@ class ChecksCodespellConfig(TypedDict, total=False): # Checks Dependabot configuration config # # The Dependabot configuration check configuration -class ChecksDependabotConfigurationConfig(TypedDict, total=False): - ignore_version_files: List[str] - types: List["_ChecksDependabotConfigurationConfigTypesItem"] - update_ignore: List["_ChecksDependabotConfigurationConfigUpdateIgnoreItem"] +ChecksDependabotConfigurationConfig = TypedDict( + "ChecksDependabotConfigurationConfig", + { + # List of files to be ignored + "ignore_version_files": List[str], + # List of check that should be present in the Dependabot config + "types": List["_ChecksDependabotConfigurationConfigTypesItem"], + # List of files to be ignored + "update_ignore": List["_ChecksDependabotConfigurationConfigUpdateIgnoreItem"], + }, + total=False, +) # Checks editorconfig @@ -187,8 +250,14 @@ class ChecksDependabotConfigurationConfig(TypedDict, total=False): # Checks editorconfig config # # The editorconfig configuration check configuration -class ChecksEditorconfigConfig(TypedDict, total=False): - properties: Dict[str, Dict[str, str]] +ChecksEditorconfigConfig = TypedDict( + "ChecksEditorconfigConfig", + { + # The key = value that should be present in the configuration + "properties": Dict[str, Dict[str, str]], + }, + total=False, +) # checks eof @@ -214,8 +283,14 @@ class ChecksEditorconfigConfig(TypedDict, total=False): # checks isort config # # The isort check configuration -class ChecksIsortConfig(TypedDict, total=False): - ignore_patterns_re: List[str] +ChecksIsortConfig = TypedDict( + "ChecksIsortConfig", + { + # List of regular expression that should be ignored + "ignore_patterns_re": List[str], + }, + total=False, +) # Checks Prettier @@ -229,9 +304,15 @@ class ChecksIsortConfig(TypedDict, total=False): # Checks Prettier config # # The Prettier check configuration -class ChecksPrettierConfig(TypedDict, total=False): - properties: Dict[str, Any] - ignore_patterns_re: List[str] +ChecksPrettierConfig = TypedDict( + "ChecksPrettierConfig", + { + "properties": Dict[str, Any], + # List of regular expression that should be ignored + "ignore_patterns_re": List[str], + }, + total=False, +) # Checks print config @@ -265,10 +346,17 @@ class ChecksPrettierConfig(TypedDict, total=False): # checks setup config # # Check the typing options in setup.cfg and in setup.py -class ChecksSetupConfig(TypedDict, total=False): - ignore_file: List[str] - cfg: Dict[str, Dict[str, str]] - classifiers: List[str] +ChecksSetupConfig = TypedDict( + "ChecksSetupConfig", + { + # list of files to be ignored + "ignore_file": List[str], + "cfg": Dict[str, Dict[str, str]], + # list of required classifiers + "classifiers": List[str], + }, + total=False, +) # checks versions @@ -282,19 +370,37 @@ class ChecksSetupConfig(TypedDict, total=False): # checks versions config # # The version check configuration -class ChecksVersionsConfig(TypedDict, total=False): - audit: bool - backport_labels: bool - branches: bool - extra_versions: List[str] - rebuild: Union["ChecksVersionsRebuild", Literal[False]] +ChecksVersionsConfig = TypedDict( + "ChecksVersionsConfig", + { + # Check the versions in the audit workflow + "audit": bool, + # Check the versions of the backport labels + "backport_labels": bool, + # Check the versions of the protected branches + "branches": bool, + # Versions that are not in the `SECURITY.md` but should still be consided + "extra_versions": List[str], + # Check the versions in the rebuild workflows + # + # oneOf + "rebuild": Union["ChecksVersionsRebuild", Literal[False]], + }, + total=False, +) # checks versions rebuild # # Check the versions in the rebuild workflows -class ChecksVersionsRebuild(TypedDict, total=False): - files: List[str] +ChecksVersionsRebuild = TypedDict( + "ChecksVersionsRebuild", + { + # The workflows files name + "files": List[str], + }, + total=False, +) # checks workflows @@ -308,36 +414,69 @@ class ChecksVersionsRebuild(TypedDict, total=False): # checks workflows config # # The workflows checks configuration -class ChecksWorkflowsConfig(TypedDict, total=False): - images_blacklist: List[str] - timeout: bool +ChecksWorkflowsConfig = TypedDict( + "ChecksWorkflowsConfig", + { + # The images that shouldn't be used + "images_blacklist": List[str], + # A timeout should be present + "timeout": bool, + }, + total=False, +) # configuration # # C2C CI utils configuration file -class Configuration(TypedDict, total=False): - audit: "Audit" - checks: "Checks" - publish: "Publish" - version: "Version" +Configuration = TypedDict( + "Configuration", + { + # WARNING: The required are not correctly taken in account, + # See: https://github.com/camptocamp/jsonschema-gentypes/issues/6 + "audit": "Audit", + # WARNING: The required are not correctly taken in account, + # See: https://github.com/camptocamp/jsonschema-gentypes/issues/6 + "checks": "Checks", + # WARNING: The required are not correctly taken in account, + # See: https://github.com/camptocamp/jsonschema-gentypes/issues/6 + "publish": "Publish", + # WARNING: The required are not correctly taken in account, + # See: https://github.com/camptocamp/jsonschema-gentypes/issues/6 + "version": "Version", + }, + total=False, +) # Print versions # # The print versions configuration -class PrintVersions(TypedDict, total=False): - versions: List["_PrintVersionsVersionsItem"] +PrintVersions = TypedDict( + "PrintVersions", + { + "versions": List["_PrintVersionsVersionsItem"], + }, + total=False, +) # Publish # # The publishing configurations -class Publish(TypedDict, total=False): - docker: "PublishDocker" - pypi: "PublishPypi" - google_calendar: "PublishGoogleCalendar" - print_versions: "PrintVersions" +Publish = TypedDict( + "Publish", + { + "docker": "PublishDocker", + "pypi": "PublishPypi", + "helm": "PublishHelm", + "google_calendar": "PublishGoogleCalendar", + # WARNING: The required are not correctly taken in account, + # See: https://github.com/camptocamp/jsonschema-gentypes/issues/6 + "print_versions": "PrintVersions", + }, + total=False, +) # Publish Docker @@ -351,22 +490,44 @@ class Publish(TypedDict, total=False): # Publish Docker config # # The configuration used to publish on Docker -class PublishDockerConfig(TypedDict, total=False): - images: List["PublishDockerImage"] - repository: Dict[str, "PublishDockerRepository"] +PublishDockerConfig = TypedDict( + "PublishDockerConfig", + { + # List of images to be published + "images": List["PublishDockerImage"], + # The repository where we should publish the images + "repository": Dict[str, "PublishDockerRepository"], + }, + total=False, +) # Publish Docker image -class PublishDockerImage(TypedDict, total=False): - group: str - name: str - tags: List[str] +PublishDockerImage = TypedDict( + "PublishDockerImage", + { + # The image is in the group, should be used with the --group option of c2cciutils-publish script + "group": str, + # The image name + "name": str, + # The tag name, will be formatted with the version=, the image with version=latest should be present when we call the c2cciutils-publish script + "tags": List[str], + }, + total=False, +) # Publish Docker repository -class PublishDockerRepository(TypedDict, total=False): - server: str - versions: List[str] +PublishDockerRepository = TypedDict( + "PublishDockerRepository", + { + # The server URL + "server": str, + # The kind or version that should be published, tag, branch or value of the --version argument of the c2cciutils-publish script + "versions": List[str], + }, + total=False, +) # Publish Google calendar @@ -380,8 +541,36 @@ class PublishDockerRepository(TypedDict, total=False): # Publish Google calendar config # # The configuration to publish on Google Calendar -class PublishGoogleCalendarConfig(TypedDict, total=False): - on: List[str] +PublishGoogleCalendarConfig = TypedDict( + "PublishGoogleCalendarConfig", + { + "on": List[str], + }, + total=False, +) + + +# publish helm +# +# Configuration to publish Helm charts on GitHub release +# +# oneOf +PublishHelm = Union["PublishHelmConfig", Literal[False]] + + +# publish helm config +# +# Configuration to publish on Helm charts on GitHub release +PublishHelmConfig = TypedDict( + "PublishHelmConfig", + { + # The folders that will be published + "folders": List[str], + # The kind or version that should be published, tag, branch or value of the --version argument of the c2cciutils-publish script + "versions": List[str], + }, + total=False, +) # publish pypi @@ -395,25 +584,44 @@ class PublishGoogleCalendarConfig(TypedDict, total=False): # publish pypi config # # Configuration to publish on pypi -class PublishPypiConfig(TypedDict, total=False): - packages: List["PublishPypiPackage"] - versions: List[str] +PublishPypiConfig = TypedDict( + "PublishPypiConfig", + { + # The configuration of packages that will be published + "packages": List["PublishPypiPackage"], + # The kind or version that should be published, tag, branch or value of the --version argument of the c2cciutils-publish script + "versions": List[str], + }, + total=False, +) # publish pypi package # # The configuration of package that will be published -class PublishPypiPackage(TypedDict, total=False): - group: str - path: str +PublishPypiPackage = TypedDict( + "PublishPypiPackage", + { + # The image is in the group, should be used with the --group option of c2cciutils-publish script + "group": str, + # The path of the pypi package + "path": str, + }, + total=False, +) # Version # # The version configurations -class Version(TypedDict, total=False): - branch_to_version_re: "VersionTransform" - tag_to_version_re: "VersionTransform" +Version = TypedDict( + "Version", + { + "branch_to_version_re": "VersionTransform", + "tag_to_version_re": "VersionTransform", + }, + total=False, +) # Version transform @@ -422,9 +630,16 @@ class Version(TypedDict, total=False): VersionTransform = List["_VersionTransformItem"] -class _ChecksDependabotConfigurationConfigTypesItem(TypedDict, total=False): - ecosystem: str - filename: str +_ChecksDependabotConfigurationConfigTypesItem = TypedDict( + "_ChecksDependabotConfigurationConfigTypesItem", + { + # The use ecosystem + "ecosystem": str, + # The use filename + "filename": str, + }, + total=False, +) _ChecksDependabotConfigurationConfigUpdateIgnoreItem = TypedDict( @@ -463,15 +678,30 @@ class _ChecksDependabotConfigurationConfigTypesItem(TypedDict, total=False): ) -class _ChecksRequiredWorkflowsConfigAdditionalpropertiesOneof0StepsItem(TypedDict, total=False): - env: List[str] - run_re: str +_ChecksRequiredWorkflowsConfigAdditionalpropertiesOneof0StepsItem = TypedDict( + "_ChecksRequiredWorkflowsConfigAdditionalpropertiesOneof0StepsItem", + { + # The required environment variable + "env": List[str], + # The required regular expression of the run part + "run_re": str, + }, + total=False, +) -class _PrintVersionsVersionsItem(TypedDict, total=False): - cmd: List[str] - name: str - prefix: str +_PrintVersionsVersionsItem = TypedDict( + "_PrintVersionsVersionsItem", + { + # The command that should be used + "cmd": List[str], + # The name + "name": str, + # Prefix added when we print the version + "prefix": str, + }, + total=False, +) _VersionTransformItem = TypedDict( diff --git a/c2cciutils/publish.py b/c2cciutils/publish.py index 1ed172775..db9c55a00 100644 --- a/c2cciutils/publish.py +++ b/c2cciutils/publish.py @@ -12,6 +12,7 @@ import uuid from typing import Optional +import ruamel.yaml from google.auth.transport.requests import Request from google.oauth2.credentials import Credentials from google_auth_oauthlib.flow import InstalledAppFlow @@ -355,3 +356,65 @@ def docker( print("With error") return False return True + + +def helm(folder: str, version: str, owner: str, repo: str, commit_sha: str, token: str) -> bool: + """ + Publish to pypi. + + Arguments: + folder: The folder to be published + version: The version that will be published + owner: The GitHub repository owner + repo: The GitHub repository name + commit_sha: The sha of the current commit + token: The GitHub token + """ + + print(f"::group::Publishing Helm chart from '{folder}' to GitHub release") + sys.stdout.flush() + sys.stderr.flush() + + try: + yaml_ = ruamel.yaml.YAML() # type: ignore + with open(os.path.join(folder, "Chart.yaml")) as open_file: + chart = yaml_.load(open_file) + chart["version"] = version + with open(os.path.join(folder, "Chart.yaml"), "w") as open_file: + chart = yaml_.dump(chart, open_file) + + subprocess.run(["cr", "package", folder], check=True) + subprocess.run( + [ + "cr", + "upload", + f"--owner={owner}", + f"--git-repo={repo}", + f"--commit={commit_sha}", + "--release-name-template={{ .Version }}", + f"--token={token}", + ], + check=True, + ) + subprocess.run(["mkdir", ".cr-index"], check=True) + subprocess.run( + [ + "cr", + "index", + f"--owner={owner}", + f"--git-repo={repo}", + f"--charts-repo=https://{owner}.github.io/{repo}", + "--push", + "--release-name-template={{ .Version }}", + f"--token={token}", + ], + check=True, + ) + + print("::endgroup::") + except subprocess.CalledProcessError as exception: + print(f"Error: {exception}") + print("::endgroup::") + print("With error") + return False + return True diff --git a/c2cciutils/schema.json b/c2cciutils/schema.json index 8f47ee383..6381443fe 100644 --- a/c2cciutils/schema.json +++ b/c2cciutils/schema.json @@ -571,6 +571,36 @@ } ] }, + "publish_helm": { + "title": "publish helm", + "description": "Configuration to publish Helm charts on GitHub release", + "oneOf": [ + { + "title": "publish helm config", + "description": "Configuration to publish on Helm charts on GitHub release", + "type": "object", + "properties": { + "folders": { + "description": "The folders that will be published", + "type": "array", + "items": { + "type": "string" + } + }, + "versions": { + "description": "The kind or version that should be published, tag, branch or value of the --version argument of the c2cciutils-publish script", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + { + "const": false + } + ] + }, "print_versions": { "title": "Print versions", "description": "The print versions configuration", @@ -662,6 +692,7 @@ "properties": { "docker": { "$ref": "#/definitions/publish_docker" }, "pypi": { "$ref": "#/definitions/publish_pypi" }, + "helm": { "$ref": "#/definitions/publish_helm" }, "google_calendar": { "$ref": "#/definitions/publish_google_calendar" }, "print_versions": { "$ref": "#/definitions/print_versions" } } diff --git a/c2cciutils/scripts/publish.py b/c2cciutils/scripts/publish.py index 203a538e3..9be1750de 100644 --- a/c2cciutils/scripts/publish.py +++ b/c2cciutils/scripts/publish.py @@ -7,9 +7,13 @@ import argparse import os import re +import subprocess import sys +import tarfile from typing import Match, Optional, cast +import requests + import c2cciutils.configuration import c2cciutils.publish from c2cciutils.publish import GoogleCalendar @@ -144,23 +148,18 @@ def main() -> None: c2cciutils.configuration.PublishPypiConfig, config.get("publish", {}).get("pypi", {}) if config.get("publish", {}).get("pypi", False) else {}, ) - for package in pypi_config["packages"]: - if package.get("group") == args.group: - publish = version_type in pypi_config.get("versions", []) - if args.dry_run: - - print( - "{} '{}' to pypi, skipping (dry run)".format( - "Publishing" if publish else "Checking", package.get("path") + if pypi_config: + for package in pypi_config["packages"]: + if package.get("group") == args.group: + publish = version_type in pypi_config.get("versions", []) + if args.dry_run: + print( + "{} '{}' to pypi, skipping (dry run)".format( + "Publishing" if publish else "Checking", package.get("path") + ) ) - ) - else: - success &= c2cciutils.publish.pip(package, version, version_type, publish) - - docker_config = cast( - c2cciutils.configuration.PublishDockerConfig, - config.get("publish", {}).get("docker", {}) if config.get("publish", {}).get("docker", False) else {}, - ) + else: + success &= c2cciutils.publish.pip(package, version, version_type, publish) google_calendar = None google_calendar_config = cast( @@ -169,29 +168,84 @@ def main() -> None: if config.get("publish", {}).get("google_calendar", False) else {}, ) - for image_conf in docker_config.get("images", []): - if image_conf.get("group", "") == args.group: - for tag_config in image_conf.get("tags", []): - tag_src = tag_config.format(version="latest") - tag_dst = tag_config.format(version=version) - for name, conf in docker_config.get("repository", {}).items(): - if version_type in conf.get("versions", []): - if args.dry_run: - print( - "Publishing {}:{} to {}, skipping (dry run)".format( - image_conf["name"], tag_dst, name + + docker_config = cast( + c2cciutils.configuration.PublishDockerConfig, + config.get("publish", {}).get("docker", {}) if config.get("publish", {}).get("docker", False) else {}, + ) + if docker_config: + for image_conf in docker_config.get("images", []): + if image_conf.get("group", "") == args.group: + for tag_config in image_conf.get("tags", []): + tag_src = tag_config.format(version="latest") + tag_dst = tag_config.format(version=version) + for name, conf in docker_config.get("repository", {}).items(): + if version_type in conf.get("versions", []): + if args.dry_run: + print( + "Publishing {}:{} to {}, skipping (dry run)".format( + image_conf["name"], tag_dst, name + ) ) - ) - else: - success &= c2cciutils.publish.docker(conf, name, image_conf, tag_src, tag_dst) - if version_type in google_calendar_config.get("on", []): - if not google_calendar: - google_calendar = GoogleCalendar() - summary = "{}:{}".format(image_conf["name"], tag_dst) - description = "Published on: {}\nFor version type: {}".format( - ", ".join(docker_config["repository"].keys()), version_type + else: + success &= c2cciutils.publish.docker(conf, name, image_conf, tag_src, tag_dst) + if version_type in google_calendar_config.get("on", []): + if not google_calendar: + google_calendar = GoogleCalendar() + summary = "{}:{}".format(image_conf["name"], tag_dst) + description = "Published on: {}\nFor version type: {}".format( + ", ".join(docker_config["repository"].keys()), version_type + ) + google_calendar.create_event(summary, description) + + helm_config = cast( + c2cciutils.configuration.PublishHelmConfig, + config.get("publish", {}).get("helm", {}) if config.get("publish", {}).get("helm", False) else {}, + ) + if helm_config and helm_config["folders"] and version_type in helm_config.get("versions", []): + url = "https://github.com/helm/chart-releaser/releases/download/v1.2.1/chart-releaser_1.2.1_linux_amd64.tar.gz" + response = requests.get(url, stream=True) + file = tarfile.open(fileobj=response.raw, mode="r:gz") + file.extractall(path=os.path.expanduser("~/.local/bin")) + + owner, repo = c2cciutils.get_repository().split("/") + commit_sha = ( + subprocess.run(["git", "rev-parse", "HEAD"], check=True, stdout=subprocess.PIPE) + .stdout.strip() + .decode() + ) + token = ( + os.environ["GITHUB_TOKEN"].strip() + if "GITHUB_TOKEN" in os.environ + else c2cciutils.gopass("gs/ci/github/token/gopass") + ) + assert token is not None + if version_type == "version_branch": + last_tag = ( + subprocess.run( + ["git", "describe", "--abbrev=0", "--tags"], check=True, stdout=subprocess.PIPE + ) + .stdout.strip() + .decode() + ) + expression = re.compile(r"^[0-9]+\.[0-9]+\.[0-9]+$") + while expression.match(last_tag) is None: + last_tag = ( + subprocess.run( + ["git", "describe", "--abbrev=0", "--tags", f"{last_tag}^"], + check=True, + stdout=subprocess.PIPE, ) - google_calendar.create_event(summary, description) + .stdout.strip() + .decode() + ) + + versions = last_tag.split(".") + versions[-1] = str(int(versions[-1]) + 1) + version = ".".join(versions) + + for folder in helm_config["folders"]: + success &= c2cciutils.publish.helm(folder, version, owner, repo, commit_sha, token) if not success: sys.exit(1) diff --git a/jsonschema-gentypes.yaml b/jsonschema-gentypes.yaml index ae581f11d..f177fed0f 100644 --- a/jsonschema-gentypes.yaml +++ b/jsonschema-gentypes.yaml @@ -3,8 +3,6 @@ headers: | Automatically generated file from a JSON schema. """ callbacks: - - - pyupgrade - - --py38-plus - - black - - isort generate: diff --git a/test/helmchart/Chart.yaml b/test/helmchart/Chart.yaml new file mode 100644 index 000000000..4dc9b9891 --- /dev/null +++ b/test/helmchart/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v2 +appVersion: '1.0' +description: A Helm chart for Kubernetes +name: test +version: 1.0.0