Skip to content

Commit

Permalink
Added release kinds to allow creating many valhalla.yml files to defi…
Browse files Browse the repository at this point in the history
…ne different processes
  • Loading branch information
pz2 committed May 18, 2024
1 parent d7262f5 commit 1f2ceb4
Show file tree
Hide file tree
Showing 14 changed files with 226 additions and 26 deletions.
25 changes: 21 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,15 +104,33 @@ current file. Currently, you can only inherit once and from one URL, so it means
contains
`extends` keyword, it won't be evaluated.

**Proxy**
## 🔀 many use cases at once! (different release kinds)

TODO
valhalla supports different use cases. F.e. you want to have ability to create minor release and hotfix
but these processes have different steps. You can do it!

## 🏴󠁣󠁤󠁥󠁱󠁿 variables
What you have to do is to define 2 files:

- valhalla.yml
- valhalla-hotfix.yml

And now, when you want to start one of this process:

- to create minor release using `valhalla.yml` create branch matching regex: `release-*`
- to create hotfix release using `valhalla-hotfix.yml` create branch matching regex: `release-hotfix-*`

This is only example, and you can define any suffix, f.e `valhalla-super-release.yml` needs
branch `release-super-release-*`

*You can only define f.e. `valhalla-minor.yml` and you do not need `valhalla.yml`, but your branches name triggering
release must meet convention*

## 🔢 variables

**Use `{}` to evaluate variable to value f.e. `{FOOBAR}`**

**hierarchy (from most important):**

- predefined variables
- custom variables
- environment variables
Expand Down Expand Up @@ -148,7 +166,6 @@ merge_request:
**It is really useful with `extends` mechanism, f.e. define general template with `variables`
which will be overriden in child `valhalla.yml`.**


### 🐛 environment variables

Valhalla allows you to use any variable defined in your environment system, it is useful f.e when you
Expand Down
2 changes: 1 addition & 1 deletion __main__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from valhalla.main import start

if __name__ == '__main__':
start()
start()
60 changes: 55 additions & 5 deletions test/ci_provider/gitlab/get_version_test.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,79 @@
import unittest
from unittest.mock import patch

from valhalla.ci_provider.gitlab.get_version import get_version_number_to_release
from valhalla.ci_provider.gitlab.get_version import get_version_to_release
from valhalla.version.version_to_release import ReleaseKind


class GetVersionTest(unittest.TestCase):

@patch('os.environ.get')
def test_release_branch(self, mock_env_get):
# given:
mock_env_get.return_value = 'release-1.0.0'
result = get_version_number_to_release()
self.assertEqual(result, '1.0.0')
release_kinds = [ReleaseKind("valhalla.yml", "", ".")]

# when:
result = get_version_to_release(release_kinds)

# then:
self.assertEqual(result.version_number_to_release, '1.0.0')
self.assertEqual(result.release_kind.filename, "valhalla.yml")
self.assertEqual(result.get_config_file_path(), "./valhalla.yml")

@patch('os.environ.get')
@patch('valhalla.ci_provider.gitlab.get_version.exit')
def test_non_release_branch(self, mock_exit, mock_env_get):
# given:
mock_env_get.return_value = 'feature-branch'
result = get_version_number_to_release()
release_kinds = [ReleaseKind("valhalla.yml", "", ".")]

# when:
result = get_version_to_release(release_kinds)

# then:
self.assertIsNone(result)
mock_exit.assert_called_with(-1)

@patch('os.environ.get')
@patch('valhalla.ci_provider.gitlab.get_version.exit')
def test_no_ci_commit_branch(self, mock_exit, mock_env_get):
# given:
mock_env_get.return_value = None
result = get_version_number_to_release()
release_kinds = [ReleaseKind("valhalla.yml", "", ".")]

# when:
result = get_version_to_release(release_kinds)

# then:
self.assertIsNone(result)
mock_exit.assert_called_with(-1)

@patch('os.environ.get')
def test_release_hotfix_branch(self, mock_env_get):
# given:
mock_env_get.return_value = 'release-hotfix-1.2.3'
release_kinds = [ReleaseKind("valhalla.yml", "", "."),
ReleaseKind("valhalla-hotfix.yml", "-hotfix", ".")]

# when:
result = get_version_to_release(release_kinds)

# then:
self.assertEqual(result.version_number_to_release, '1.2.3')
self.assertEqual(result.release_kind.filename, "valhalla-hotfix.yml")
self.assertEqual(result.get_config_file_path(), "./valhalla-hotfix.yml")

@patch('os.environ.get')
@patch('valhalla.ci_provider.gitlab.get_version.exit')
def test_no_matching_valhalla_branch(self, mock_exit, mock_env_get):
# given:
mock_env_get.return_value = 'release-1.2.3'
release_kinds = [ReleaseKind("valhalla-hotfix.yml", "-hotfix", ".")]

# when:
result = get_version_to_release(release_kinds)

# then:
self.assertIsNone(result)
mock_exit.assert_called_with(-1)
Empty file added test/version/__init__.py
Empty file.
Empty file.
Empty file.
Empty file.
34 changes: 34 additions & 0 deletions test/version/version_to_release_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import unittest
from unittest.mock import patch

from valhalla.version.version_to_release import get_release_kinds


class GetValhallaReleaseKindsTest(unittest.TestCase):

def test_main_file(self):
result = get_release_kinds("./resources/test_main_file")

self.assertEqual(len(result), 1)

self.assertEqual(result[0].filename, "valhalla.yml")
self.assertEqual(result[0].suffix, "")
self.assertEqual(result[0].path, "./resources/test_main_file")

def test_main_and_hotfix_file(self):
result = get_release_kinds("./resources/test_main_and_hotfix_file")

self.assertEqual(len(result), 2)

self.assertEqual(result[0].filename, "valhalla.yml")
self.assertEqual(result[0].suffix, "")
self.assertEqual(result[0].path, "./resources/test_main_and_hotfix_file")

self.assertEqual(result[1].filename, "valhalla-hotfix.yml")
self.assertEqual(result[1].suffix, "-hotfix")
self.assertEqual(result[1].path, "./resources/test_main_and_hotfix_file")

@patch('valhalla.version.version_to_release.exit')
def test_empty(self, mock_exit):
result = get_release_kinds("./resources/empty")
mock_exit.assert_called_with(-1)
58 changes: 52 additions & 6 deletions valhalla/ci_provider/gitlab/get_version.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,69 @@
import os
from typing import List

from valhalla.common.logger import info, error
from valhalla.version.version_to_release import VersionToRelease, ReleaseKind

BASE_PREFIX = "release-"

def get_version_number_to_release() -> str:

def get_version_to_release(release_kinds: List[ReleaseKind]) -> VersionToRelease:
ci_commit_branch = os.environ.get('CI_COMMIT_BRANCH')

if ci_commit_branch:
info(f'Name of branch is: {ci_commit_branch}')

if ci_commit_branch.startswith('release-'):
project_version = ci_commit_branch[len('release-'):]
info(f'Project version that is going to be released: {project_version}')
return project_version

# first we search for specific release kinds
for release_kind in release_kinds:
if release_kind.suffix != "":
prefix = __get_branch_prefix(release_kind)
if ci_commit_branch.startswith(prefix):
return __matched(ci_commit_branch, prefix, release_kind)

# now if specific release kind not found we search for main
for release_kind in release_kinds:
if release_kind.suffix == "":
prefix = BASE_PREFIX
if ci_commit_branch.startswith(prefix):
return __matched(ci_commit_branch, prefix, release_kind)

__no_matching_release_kind(ci_commit_branch, release_kinds)

else:
error('This is not a release branch! This script should not be run! The name of the branch must be release-X.X.X')
error('This is not a release branch! This script should not be run! The name of the branch must be '
'release-X.X.X')
error('Check valhalla configration and manual !')
exit(-1)
else:
error('CI_COMMIT_BRANCH environment variable is not set. Are you using GitLab CI? If not change your '
'valhalla configration')
'valhalla configration!')
exit(-1)


def __get_branch_prefix(release_kind: ReleaseKind) -> str:
prefix = (BASE_PREFIX + release_kind.suffix).replace("--", "-")
if prefix.endswith("-"):
return prefix
else:
return prefix + "-"


def __matched(ci_commit_branch: str, prefix: str, release_kind: ReleaseKind) -> VersionToRelease:
info(f"Branch name {ci_commit_branch} has prefix {prefix} and matches with release kind {release_kind}")
project_version = ci_commit_branch[len(prefix):]
info(f'Project version that is going to be released: {project_version}')
return VersionToRelease(project_version, release_kind)


def __no_matching_release_kind(ci_commit_branch: str, release_kinds: List[ReleaseKind]):
error('This is a release branch, but valhalla could not find matching valhalla.yml file!')
error(f'Name of branch is: {ci_commit_branch}')
for kind in release_kinds:
error(f'Available release kind: {kind}')
prefix = __get_branch_prefix(kind)
error(f'To match this release kind you branch must starts with {prefix} f.e {prefix}1.5.3')

error('Create branch name with correct prefix to the release kind that you want to match with and start!')
exit(-1)
6 changes: 3 additions & 3 deletions valhalla/common/get_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,10 @@ def __repr__(self):
f" )"


def get_config(path) -> Config:
def get_config(path: str) -> Config:
info(f"Trying to load config from: {path}")
try:
with open(path) as f:
info(f"Trying to load config from: {path}")
yml_dict = safe_load(f)

extends_list = get_from_dict(yml_dict, 'extends', False)
Expand Down Expand Up @@ -192,7 +192,7 @@ def get_release_description_config_part(description_dict: dict) -> ReleaseDescri
def get_release_assets_config_part(assets_dict: dict) -> ReleaseAssetsConfig:
if assets_dict is None:
return ReleaseAssetsConfig([])

links_dict = assets_dict['links']
links = get_release_assets_links_config_part(links_dict)

Expand Down
17 changes: 10 additions & 7 deletions valhalla/main.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,34 @@
from valhalla.ci_provider.get_token import get_valhalla_token
from valhalla.ci_provider.gitlab.get_version import get_version_to_release
from valhalla.ci_provider.gitlab.merge_request import GitLabValhallaMergeRequest
from valhalla.ci_provider.gitlab.release import GitLabValhallaRelease
from valhalla.commit import before
from valhalla.ci_provider.gitlab.get_version import get_version_number_to_release
from valhalla.commit.commit import GitRepository
from valhalla.common.get_config import get_config, Config, CommitConfig, MergeRequestConfig
from valhalla.common.get_config import get_config, CommitConfig, MergeRequestConfig, Config
from valhalla.common.logger import info, init_logger
from valhalla.common.resolver import init_str_resolver, init_str_resolver_custom_variables
from valhalla.release.assets import Assets
from valhalla.release.description import Description
from valhalla.version.version_to_release import get_release_kinds


def start():
print(f'Release the Valhalla!')

version_to_release = get_version_number_to_release()
release_kinds = get_release_kinds(".")

version_to_release = get_version_to_release(release_kinds)
token = get_valhalla_token()
init_logger(token)

init_str_resolver(version_to_release, token)
init_str_resolver(version_to_release.version_number_to_release, token)

config = get_config("./valhalla.yml")
config = get_config(version_to_release.get_config_file_path())
init_str_resolver_custom_variables(config.variables)

commit(config.commit_before_release, token)

create_release(config, version_to_release)
create_release(config, version_to_release.version_number_to_release)

commit(config.commit_after_release, token)

Expand All @@ -45,7 +48,7 @@ def create_merge_request(merge_request_config: MergeRequestConfig):
info("merge_request.enabled is False in valhalla.yml, skipping")


def create_release(config, version_to_release):
def create_release(config: Config, version_to_release: str):
info("Preparing to create release")
release = GitLabValhallaRelease()
description = Description(config.release_config.description_config)
Expand Down
Empty file added valhalla/release/__init__.py
Empty file.
Empty file added valhalla/version/__init__.py
Empty file.
50 changes: 50 additions & 0 deletions valhalla/version/version_to_release.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import re
import os

from typing import List

from valhalla.common.logger import info, error


class ReleaseKind:

def __init__(self, filename: str, suffix: str, path: str):
self.filename = filename
self.suffix = suffix
self.path = path

def __repr__(self):
return f"filename={self.filename}, suffix={self.suffix}, path={self.path}"


class VersionToRelease:

def __init__(self, version_number_to_release: str, release_kind: ReleaseKind):
self.version_number_to_release = version_number_to_release
self.release_kind = release_kind

def get_config_file_path(self):
return self.release_kind.path + "/" + self.release_kind.filename


def get_release_kinds(path: str) -> List[ReleaseKind]:
info(f"Searching for valhalla*.yml files in: {path}")
pattern = re.compile(r'valhalla(.*)\.yml')
release_kinds = []

for root, dirs, files in os.walk(path):
for file in files:
match = pattern.match(file)
if match:
release_kinds.append(ReleaseKind(file, match.group(1), path))

for kind in release_kinds:
info(f"Found: {kind}")

if len(release_kinds) == 0:
error("Cloud not find any valhalla file! You have to have at least one file matching valhalla*.yml f.e "
"valhalla.yml. You can define valhalla-hotfix.yml but remember to use release-hotfix-* branch to start"
"valhalla proces :)")
exit(-1)

return release_kinds

0 comments on commit 1f2ceb4

Please sign in to comment.