From a3b637023a26b950937f7bf5ab41843ab0efe631 Mon Sep 17 00:00:00 2001 From: marwin1991 Date: Sun, 17 Dec 2023 00:11:28 +0100 Subject: [PATCH] added ability to extend valhalla.yml configs and keep global configuration --- README.md | 25 +++++++-- test/extends/__init__.py | 0 test/extends/merge_dicts_test.py | 85 +++++++++++++++++++++++++++++ valhalla.yml | 5 ++ valhalla/common/get_config.py | 8 ++- valhalla/extends/ValhallaExtends.py | 43 +++++++++++++++ valhalla/extends/__init__.py | 0 valhalla/extends/merge_dicts.py | 23 ++++++++ 8 files changed, 183 insertions(+), 6 deletions(-) create mode 100644 test/extends/__init__.py create mode 100644 test/extends/merge_dicts_test.py create mode 100644 valhalla/extends/ValhallaExtends.py create mode 100644 valhalla/extends/__init__.py create mode 100644 valhalla/extends/merge_dicts.py diff --git a/README.md b/README.md index 44791c4..32a6e6b 100644 --- a/README.md +++ b/README.md @@ -23,14 +23,13 @@ saving time, and promoting compliance with established regulations. ### ⚙️ configuration -- if using GitLab workflows - for `merge requests workflow` [(link)](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Workflows/MergeRequest-Pipelines.gitlab-ci.yml) - you have to add `if: '$CI_COMMIT_BRANCH =~ /^release-*/` to global workflow configuration - create `valhalla.yml` in your project (check out [examples](https://github.com/logchange/valhalla/tree/master/examples)) ```yml # This file is used by valhalla tool to create release 🌌 # Visit https://github.com/logchange/valhalla and leave a star 🌟 # More info about configuration you can find https://github.com/logchange/valhalla#%EF%B8%8F-configuration ⬅️ +extends: # You can extend any file from URL! This helps keep configuration in one place! + - https://raw.githubusercontent.com/logchange/valhalla/master/valhalla-extends.yml git_host: gitlab # your project ci provider, supported [gitlab] commit_before_release: # define actions which have to happen before release and output should be committed enabled: True # if this is True commands from before will be performed and committed to branch @@ -82,6 +81,20 @@ merge_request: extensions like `release-2.10.4-RC`. 2. Valhalla will do everything for you 🚀 +### inheritance + +To simplify managing multimple repositories, you can use `extends:` keyword. + +```yml +extends: + - https://raw.githubusercontent.com/logchange/valhalla/master/valhalla.yml +``` + +You can point to any URL that is `valhalla.yml` and it will be loaded and then override by values from +current file. Currently, you can only inherit once, co it means if you inherit from a file, that also contains +`extends` keyword, it won't be evaluated. + + ### 🖖 string predefined variables **Use `{}` to evaluate variable to value f.e. `{VERSION}`** @@ -92,7 +105,9 @@ merge_request: ### 🦊 .gitlab-ci.yml -- you have to add `if: '$CI_COMMIT_BRANCH =~ /^release-*/` to global workflow configuration +- if using GitLab workflows + for `merge requests workflow` [(link)](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Workflows/MergeRequest-Pipelines.gitlab-ci.yml) + you have to add `if: '$CI_COMMIT_BRANCH =~ /^release-*/` to global workflow configuration ```yml @@ -100,6 +115,6 @@ workflows: if: '$CI_COMMIT_BRANCH =~ /^release-*/ release: - stage: + stage: ``` \ No newline at end of file diff --git a/test/extends/__init__.py b/test/extends/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/extends/merge_dicts_test.py b/test/extends/merge_dicts_test.py new file mode 100644 index 0000000..1ea3114 --- /dev/null +++ b/test/extends/merge_dicts_test.py @@ -0,0 +1,85 @@ +import unittest + +from valhalla.extends.merge_dicts import merge + + +class MergeDictsTest(unittest.TestCase): + + def test_merge_dicts(self): + parent = { + "commit_before_release": { + "msg": "ABC Releasing version {VERSION}", + "before": [ + "parent element 1", + "parent element 2" + ], + }, + "merge_request": { + "title": "parent title", + "description": "parent description", + }, + } + + child = { + "extends": [ + "https://raw.githubusercontent.com/logchange/valhalla/master/valhalla-extends.yml" + ], + "git_host": "gitlab", + "commit_before_release": { + "enabled": True, + "username": "Test1234", + "email": "test-valhalla@logchange.dev", + "msg": "Releasing version {VERSION}", + "before": [ + "child element 1", + "child element 2", + "child element 3" + ], + }, + "release": { + "description": { + "from_command": "cat changelog / v{VERSION} / version_summary.md" + }, + "assets": { + "links": [ + { + "name": "Documentation", + "url": "https: // google.com / q?={VERSION}", + "link_type": "other", + }, + { + "name": "Docker Image", + "url": "https://dockerhub.com/q?={VERSION}", + "link_type": "image", + }, + ] + }, + }, + "commit_after_release": { + "enabled": True, + "username": "Test1234", + "email": "test-valhalla@logchange.dev", + "msg": "Preparation for next development cycle", + "before": ['echo "test" > prepare_next_iteration.md'], + }, + "merge_request": { + "enabled": True, + "title": "child title", + "reviewers": ["peter.zmilczak", "some_uknownwnnaa"], + }, + } + + result = merge(parent, child) + + self.assertEqual(result['extends'], + ['https://raw.githubusercontent.com/logchange/valhalla/master/valhalla-extends.yml']) + self.assertEqual(result['git_host'], 'gitlab') + + self.assertEqual(result['commit_before_release']['before'], [ + "child element 1", + "child element 2", + "child element 3" + ]) + + self.assertEqual(result['merge_request']['title'], 'child title') + self.assertEqual(result['merge_request']['description'], 'parent description') diff --git a/valhalla.yml b/valhalla.yml index c6dd5f5..19c57a9 100644 --- a/valhalla.yml +++ b/valhalla.yml @@ -1,3 +1,8 @@ +# This file is used by valhalla tool to create release 🌌 +# Visit https://github.com/logchange/valhalla and leave a star 🌟 +# More info about configuration you can find https://github.com/logchange/valhalla#%EF%B8%8F-configuration ⬅️ +extends: + - https://raw.githubusercontent.com/logchange/valhalla/master/valhalla-extends.yml git_host: gitlab commit_before_release: enabled: True diff --git a/valhalla/common/get_config.py b/valhalla/common/get_config.py index 3d9509f..b40e75e 100644 --- a/valhalla/common/get_config.py +++ b/valhalla/common/get_config.py @@ -2,6 +2,7 @@ from yaml import safe_load from valhalla.common.logger import info, error, warn +from valhalla.extends.ValhallaExtends import ValhallaExtends class MergeRequestConfig: @@ -90,7 +91,8 @@ def __repr__(self): class Config: - def __init__(self, git_host: str, + def __init__(self, + git_host: str, commit_before_release: CommitConfig, release_config: ReleaseConfig, commit_after_release: CommitConfig, @@ -117,6 +119,10 @@ def get_config(path) -> Config: info(f"Trying to load config from: {path}") yml_dict = safe_load(f) + extends_list = get_from_dict(yml_dict, 'extends', False) + extends = ValhallaExtends(extends_list) + yml_dict = extends.merge(yml_dict) + git_host = yml_dict['git_host'] commit_before_release_dict = yml_dict['commit_before_release'] diff --git a/valhalla/extends/ValhallaExtends.py b/valhalla/extends/ValhallaExtends.py new file mode 100644 index 0000000..5b5fe41 --- /dev/null +++ b/valhalla/extends/ValhallaExtends.py @@ -0,0 +1,43 @@ +from typing import List + +import urllib.request +from yaml import safe_load + +from valhalla.common.logger import info, error +from valhalla.extends.merge_dicts import merge + + +def get_from_url(url): + result = "" + data = urllib.request.urlopen(url) + for line in data: + str_line = line.decode("UTF-8") + result += str_line + info("Loaded from ULR") + info("===========================================") + print(result) + info("===========================================") + return result + + +class ValhallaExtends: + + def __init__(self, extends: List[str]): + self.extends = extends + + def merge(self, valhalla_yml_dict: dict) -> dict: + if self.extends is None or len(self.extends) < 1: + info("There is nothing to extend") + return valhalla_yml_dict + elif len(self.extends) == 1: + info("There is one file to extend") + extended = get_from_url(self.extends[0]) + extended_dict = safe_load(extended) + info("yml data as dictionary to extends: " + str(extended_dict)) + info("yml data from valhalla.yml: " + str(valhalla_yml_dict)) + result = merge(extended_dict, valhalla_yml_dict) + info("final yml data: " + str(result)) + return result + else: + error("Currently you can extend only from one url!") + exit(1) diff --git a/valhalla/extends/__init__.py b/valhalla/extends/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/valhalla/extends/merge_dicts.py b/valhalla/extends/merge_dicts.py new file mode 100644 index 0000000..c11ff59 --- /dev/null +++ b/valhalla/extends/merge_dicts.py @@ -0,0 +1,23 @@ +import copy + + +def merge(parent: dict, child: dict): + parent_copy = copy.deepcopy(parent) + child_copy = copy.deepcopy(child) + + return __merge(parent_copy, child_copy) + + +def __merge(parent_org: dict, child_org: dict): + parent_copy = copy.deepcopy(parent_org) + child_copy = copy.deepcopy(child_org) + + if isinstance(child_copy, dict): + for k, v in child_copy.items(): + if k in parent_copy: + parent_copy[k] = __merge(parent_copy.get(k), v) + else: + parent_copy[k] = v + return parent_copy + else: + return child_copy