Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 37 additions & 9 deletions src/gardenlinux/features/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import argparse
import logging
import os
import re
from functools import reduce
from os import path
from typing import Any, List, Set
Expand All @@ -18,17 +19,25 @@
_ARGS_TYPE_ALLOWED = [
"cname",
"cname_base",
"container_name",
"container_tag",
"commit_id",
"features",
"platforms",
"flags",
"flavor",
"elements",
"arch",
"version",
"version_and_commit_id",
"graph",
]

RE_CAMEL_CASE_SPLITTER = re.compile("([A-Z]+|[a-z0-9])([A-Z])(?!$)")
"""
CamelCase splitter RegExp
"""


def main() -> None:
"""
Expand Down Expand Up @@ -102,15 +111,26 @@ def main() -> None:
commit_id_or_hash = cname.commit_id
version = cname.version

if arch is None or arch == "" and (args.type in ("cname", "arch")):
if (arch is None or arch == "") and (
args.type in ("cname", "container_name", "arch")
):
raise RuntimeError(
"Architecture could not be determined and no default architecture set"
)

if (
version is None
or version == ""
and (args.type in ("cname", "commit_id", "version", "version_and_commit_id"))
if (commit_id_or_hash is None or commit_id_or_hash == "") and (
args.type in ("container_tag", "commit_id", "version_and_commit_id")
):
raise RuntimeError("Commit ID not specified")

if (version is None or version == "") and (
args.type
in (
"container_tag",
"commit_id",
"version",
"version_and_commit_id",
)
):
raise RuntimeError("Version not specified and no default version set")

Expand All @@ -121,13 +141,15 @@ def main() -> None:
elif args.type in (
"cname_base",
"cname",
"container_name",
"elements",
"features",
"flags",
"flavor",
"graph",
"platforms",
):
if args.type == "graph" or len(args.ignore) > 1:
if args.type == "graph" or len(args.ignore) > 0:
features_parser = Parser(gardenlinux_root, feature_dir_name)

print_output_from_features_parser(
Expand All @@ -137,13 +159,15 @@ def main() -> None:
print_output_from_cname(args.type, cname)
elif args.type == "commit_id":
print(commit_id_or_hash[:8])
elif args.type == "container_tag":
print(re.sub("\\W+", "-", f"{version}-{commit_id_or_hash[:8]}"))
elif args.type == "version":
print(version)
elif args.type == "version_and_commit_id":
print(f"{version}-{commit_id_or_hash[:8]}")


def get_cname_base(sorted_features: List[str]):
def get_flavor(sorted_features: List[str]):
"""
Get the base cname for the feature set given.

Expand Down Expand Up @@ -265,7 +289,7 @@ def print_output_from_features_parser(

sorted_minimal_features = sort_subset(minimal_feature_set, sorted_features)

cname_base = get_cname_base(sorted_minimal_features)
cname_base = get_flavor(sorted_minimal_features)

if output_type == "cname_base":
print(cname_base)
Expand All @@ -279,7 +303,9 @@ def print_output_from_features_parser(
cname += f"-{version}-{commit_id_or_hash[:8]}"

print(cname)
if output_type == "platforms":
elif output_type == "container_name":
print(RE_CAMEL_CASE_SPLITTER.sub("\\1_\\2", cname_base).lower())
elif output_type == "platforms":
print(",".join(features_by_type["platform"]))
elif output_type == "elements":
print(",".join(features_by_type["element"]))
Expand All @@ -303,6 +329,8 @@ def print_output_from_cname(output_type: str, cname_instance: CName) -> None:
print(cname_instance.flavor)
elif output_type == "cname":
print(cname_instance.cname)
elif output_type == "container_name":
print(RE_CAMEL_CASE_SPLITTER.sub("\\1-\\2", cname_instance.flavor).lower())
elif output_type == "platforms":
print(cname_instance.feature_set_platform)
elif output_type == "elements":
Expand Down
4 changes: 2 additions & 2 deletions src/gardenlinux/features/cname_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from os.path import basename, dirname

from .__main__ import (
get_cname_base,
get_flavor,
get_minimal_feature_set,
get_version_and_commit_id_from_files,
sort_subset,
Expand Down Expand Up @@ -80,7 +80,7 @@ def main():

sorted_minimal_features = sort_subset(minimal_feature_set, sorted_features)

generated_cname = get_cname_base(sorted_minimal_features)
generated_cname = get_flavor(sorted_minimal_features)

generated_cname += f"-{cname.arch}"

Expand Down
6 changes: 3 additions & 3 deletions src/gardenlinux/features/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,15 @@ class Parser(object):
Apache License, Version 2.0
"""

_GARDENLINUX_ROOT: str = "."
_GARDENLINUX_ROOT: str = os.getenv("GL_ROOT_DIR", ".")
"""
Default GardenLinux root directory
"""

def __init__(
self,
gardenlinux_root: str | None = None,
feature_dir_name: str = "features",
gardenlinux_root: Optional[str] = None,
feature_dir_name: Optional[str] = "features",
logger: Optional[logging.Logger] = None,
):
"""
Expand Down
179 changes: 154 additions & 25 deletions tests/features/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,30 @@
import pytest

import gardenlinux.features.__main__ as fema
from gardenlinux.features import CName
from gardenlinux.features import CName, Parser

from ..constants import GL_ROOT_DIR

# -------------------------------
# Helper function tests
# -------------------------------


def test_get_cname_base():
def test_get_flavor():
# Arrange
sorted_features = ["base", "_hidden", "extra"]

# Act
result = fema.get_cname_base(sorted_features)
result = fema.get_flavor(sorted_features)

# Assert
assert result == "base_hidden-extra"


def test_get_cname_base_empty_raises():
# get_cname_base with empty iterable raises TypeError
def test_get_flavor_empty_raises():
# get_flavor with empty iterable raises TypeError
with pytest.raises(TypeError):
fema.get_cname_base([])
fema.get_flavor([])


def test_sort_return_intersection_subset():
Expand Down Expand Up @@ -146,6 +148,54 @@ def test_main_prints_arch(monkeypatch, capsys):
assert "amd64" in out


def test_main_prints_container_name(monkeypatch, capsys):
# Arrange
argv = [
"prog",
"--arch",
"amd64",
"--cname",
"container-pythonDev",
"--version",
"1.0",
"container_name",
]
monkeypatch.setattr(sys, "argv", argv)
monkeypatch.setattr(fema, "Parser", lambda *a, **kw: None)

# Act
fema.main()

# Assert
out = capsys.readouterr().out
assert "container-python-dev" in out


def test_main_prints_container_tag(monkeypatch, capsys):
# Arrange
argv = [
"prog",
"--arch",
"amd64",
"--cname",
"flav",
"--version",
"1.0",
"--commit",
"~post1",
"container_tag",
]
monkeypatch.setattr(sys, "argv", argv)
monkeypatch.setattr(fema, "Parser", lambda *a, **kw: None)

# Act
fema.main()

# Assert
out = capsys.readouterr().out.strip()
assert "1-0-post1" == out


def test_main_prints_commit_id(monkeypatch, capsys):
# Arrange
argv = ["prog", "--arch", "amd64", "--cname", "flav", "commit_id"]
Expand Down Expand Up @@ -238,14 +288,49 @@ def test_main_prints_version_and_commit_id(monkeypatch, capsys):
assert "1.2.3-abcdef12" == captured.out.strip()


def test_main_arch_raises_missing_verison(monkeypatch, capsys):
def test_main_requires_cname(monkeypatch):
# Arrange
argv = ["prog", "--arch", "amd64", "--cname", "flav", "arch"]
monkeypatch.setattr(sys, "argv", ["prog", "arch"])
monkeypatch.setattr(fema, "Parser", lambda *a, **kw: None)

# Act / Assert
with pytest.raises(SystemExit):
fema.main()


def test_main_raises_no_arch_no_default(monkeypatch):
# Arrange
# args.type == 'cname, arch is None and no default_arch set
argv = ["prog", "--cname", "flav", "cname"]
monkeypatch.setattr(sys, "argv", argv)
monkeypatch.setattr(
fema,
"Parser",
lambda *a, **kw: types.SimpleNamespace(filter=lambda *a, **k: None),
)

# Act / Assert
with pytest.raises(RuntimeError, match="Architecture could not be determined"):
fema.main()


def test_main_raises_missing_commit_id(monkeypatch, capsys):
# Arrange
argv = [
"prog",
"--arch",
"amd64",
"--cname",
"flav",
"--version",
"1.0",
"version_and_commit_id",
]
monkeypatch.setattr(sys, "argv", argv)
monkeypatch.setattr(fema, "Parser", lambda *a, **kw: None)

# Act / Assert
with pytest.raises(RuntimeError):
with pytest.raises(RuntimeError, match="Commit ID not specified"):
fema.main()


Expand Down Expand Up @@ -288,27 +373,71 @@ def sort_subset(subset, length):
assert "flav" in captured.out


def test_main_requires_cname(monkeypatch):
def test_main_with_exclude_cname_print_elements(monkeypatch, capsys):
# Arrange
monkeypatch.setattr(sys, "argv", ["prog", "arch"])
monkeypatch.setattr(fema, "Parser", lambda *a, **kw: None)
monkeypatch.setattr(
sys,
"argv",
[
"prog",
"--feature-dir",
f"{GL_ROOT_DIR}/features",
"--cname",
"kvm-gardener_prod",
"--ignore",
"cloud",
"--arch",
"amd64",
"--version",
"local",
"--commit",
"today",
"elements",
],
)

# Act / Assert
with pytest.raises(SystemExit):
fema.main()
# Act
fema.main()

# Assert
captured = capsys.readouterr().out.strip()

def test_main_raises_no_arch_no_default(monkeypatch):
assert (
"log,sap,ssh,base,server,gardener"
== captured
)


def test_main_with_exclude_cname_print_features(monkeypatch, capsys):
# Arrange
# args.type == 'cname, arch is None and no default_arch set
argv = ["prog", "--cname", "flav", "cname"]
monkeypatch.setattr(sys, "argv", argv)
monkeypatch.setattr(
fema,
"Parser",
lambda *a, **kw: types.SimpleNamespace(filter=lambda *a, **k: None),
sys,
"argv",
[
"prog",
"--feature-dir",
f"{GL_ROOT_DIR}/features",
"--cname",
"kvm-gardener_prod",
"--ignore",
"cloud",
"--arch",
"amd64",
"--version",
"local",
"--commit",
"today",
"features",
],
)

# Act / Assert
with pytest.raises(RuntimeError, match="Architecture could not be determined"):
fema.main()
# Act
fema.main()

# Assert
captured = capsys.readouterr().out.strip()

assert (
"log,sap,ssh,_boot,_ignite,kvm,_nopkg,_prod,_slim,base,server,gardener"
== captured
)
Loading
Loading