Merge pull request 'generate_test_vars: fix + add tests' (#5163) from dave into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5163
This commit is contained in:
@@ -108,13 +108,6 @@
|
|||||||
extraPythonPackages = (self'.packages.clan-app.devshellPyDeps pkgs.python3Packages);
|
extraPythonPackages = (self'.packages.clan-app.devshellPyDeps pkgs.python3Packages);
|
||||||
extraPythonPaths = [ "../../clan-cli" ];
|
extraPythonPaths = [ "../../clan-cli" ];
|
||||||
};
|
};
|
||||||
"generate-test-vars" = {
|
|
||||||
directory = "pkgs/generate-test-vars";
|
|
||||||
extraPythonPackages = [
|
|
||||||
(pkgs.python3.withPackages (ps: self'.packages.clan-cli.devshellPyDeps ps))
|
|
||||||
];
|
|
||||||
extraPythonPaths = [ "../clan-cli" ];
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
// (
|
// (
|
||||||
if pkgs.stdenv.isLinux then
|
if pkgs.stdenv.isLinux then
|
||||||
|
|||||||
@@ -77,9 +77,7 @@ in
|
|||||||
) machineModules
|
) machineModules
|
||||||
);
|
);
|
||||||
|
|
||||||
update-vars-script = "${
|
update-vars-script = "${self.packages.${hostPkgs.system}.clan-cli}/bin/clan-generate-test-vars";
|
||||||
self.packages.${hostPkgs.system}.generate-test-vars
|
|
||||||
}/bin/generate-test-vars";
|
|
||||||
|
|
||||||
relativeDir = removePrefix "${self}/" (toString config.clan.directory);
|
relativeDir = removePrefix "${self}/" (toString config.clan.directory);
|
||||||
|
|
||||||
|
|||||||
12
pkgs/clan-cli/bin/clan-generate-test-vars
Executable file
12
pkgs/clan-cli/bin/clan-generate-test-vars
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.path.insert(
|
||||||
|
0, os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
|
||||||
|
)
|
||||||
|
|
||||||
|
from clan_cli.generate_test_vars.cli import main # NOQA
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -9,7 +9,7 @@ import subprocess
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from tempfile import NamedTemporaryFile
|
from tempfile import NamedTemporaryFile
|
||||||
from typing import Any, override
|
from typing import TYPE_CHECKING, Any, override
|
||||||
|
|
||||||
from clan_cli.vars.generator import Generator
|
from clan_cli.vars.generator import Generator
|
||||||
from clan_cli.vars.prompt import PromptType
|
from clan_cli.vars.prompt import PromptType
|
||||||
@@ -20,6 +20,12 @@ from clan_lib.machines.machines import Machine
|
|||||||
from clan_lib.nix import nix_config, nix_eval, nix_test_store
|
from clan_lib.nix import nix_config, nix_eval, nix_test_store
|
||||||
from clan_lib.vars.generate import run_generators
|
from clan_lib.vars.generate import run_generators
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from clan_lib.machines.actions import (
|
||||||
|
ListOptions,
|
||||||
|
MachineResponse,
|
||||||
|
)
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
sops_priv_key = (
|
sops_priv_key = (
|
||||||
@@ -87,6 +93,26 @@ class TestFlake(Flake):
|
|||||||
full_selector = f'checks."{test_system}".{self.check_attr}.machinesCross.{system}."{machine_name}".{selector}'
|
full_selector = f'checks."{test_system}".{self.check_attr}.machinesCross.{system}."{machine_name}".{selector}'
|
||||||
return self.select(full_selector)
|
return self.select(full_selector)
|
||||||
|
|
||||||
|
# we don't want to evaluate all machines of the flake. Only the ones defined in the test
|
||||||
|
def set_machine_names(self, machine_names: list[str]) -> None:
|
||||||
|
"""Set the machine names for this flake instance to fake the machines defined by the test"""
|
||||||
|
self._machine_names = machine_names
|
||||||
|
|
||||||
|
def list_machines(
|
||||||
|
self,
|
||||||
|
opts: "ListOptions | None" = None, # noqa: ARG002
|
||||||
|
) -> "dict[str, MachineResponse]":
|
||||||
|
"""List machines of a clan"""
|
||||||
|
from clan_lib.machines.actions import ( # noqa: PLC0415
|
||||||
|
InventoryMachine,
|
||||||
|
MachineResponse,
|
||||||
|
)
|
||||||
|
|
||||||
|
res = {}
|
||||||
|
for name in self._machine_names:
|
||||||
|
res[name] = MachineResponse(data=InventoryMachine())
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
class TestMachine(Machine):
|
class TestMachine(Machine):
|
||||||
"""Machine class which is able to deal with not having an actual flake.
|
"""Machine class which is able to deal with not having an actual flake.
|
||||||
@@ -180,13 +206,13 @@ def parse_args() -> Options:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def generate_test_vars(
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
clean: bool,
|
||||||
os.environ["CLAN_NO_COMMIT"] = "1"
|
repo_root: Path,
|
||||||
opts = parse_args()
|
test_dir: Path,
|
||||||
test_dir = opts.test_dir
|
check_attr: str,
|
||||||
|
) -> None:
|
||||||
if opts.clean:
|
if clean:
|
||||||
shutil.rmtree(test_dir / "vars", ignore_errors=True)
|
shutil.rmtree(test_dir / "vars", ignore_errors=True)
|
||||||
shutil.rmtree(test_dir / "sops", ignore_errors=True)
|
shutil.rmtree(test_dir / "sops", ignore_errors=True)
|
||||||
|
|
||||||
@@ -196,25 +222,27 @@ def main() -> None:
|
|||||||
if system.endswith("-darwin"):
|
if system.endswith("-darwin"):
|
||||||
test_system = system.rstrip("darwin") + "linux"
|
test_system = system.rstrip("darwin") + "linux"
|
||||||
|
|
||||||
flake = TestFlake(opts.check_attr, test_dir, str(opts.repo_root))
|
flake = TestFlake(check_attr, test_dir, str(repo_root))
|
||||||
machine_names = get_machine_names(
|
machine_names = get_machine_names(
|
||||||
opts.repo_root,
|
repo_root,
|
||||||
opts.check_attr,
|
check_attr,
|
||||||
test_system,
|
test_system,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
flake.set_machine_names(machine_names)
|
||||||
|
|
||||||
flake.precache(
|
flake.precache(
|
||||||
[
|
[
|
||||||
f"checks.{test_system}.{opts.check_attr}.machinesCross.{system}.{{{','.join(machine_names)}}}.config.clan.core.vars.generators.*.validationHash",
|
f"checks.{test_system}.{check_attr}.machinesCross.{system}.{{{','.join(machine_names)}}}.config.clan.core.vars.generators.*.validationHash",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
# This hack is necessary because the sops store uses flake.path to find the machine keys
|
# This hack is necessary because the sops store uses flake.path to find the machine keys
|
||||||
# This hack does not work because flake.invalidate_cache resets _path
|
# This hack does not work because flake.invalidate_cache resets _path
|
||||||
flake._path = opts.test_dir # noqa: SLF001
|
flake._path = test_dir # noqa: SLF001
|
||||||
|
|
||||||
machines = [
|
machines = [
|
||||||
TestMachine(name, flake, test_dir, opts.check_attr) for name in machine_names
|
TestMachine(name, flake, test_dir, check_attr) for name in machine_names
|
||||||
]
|
]
|
||||||
user = "admin"
|
user = "admin"
|
||||||
admin_key_path = Path(test_dir.resolve() / "sops" / "users" / user / "key.json")
|
admin_key_path = Path(test_dir.resolve() / "sops" / "users" / user / "key.json")
|
||||||
@@ -259,5 +287,17 @@ def main() -> None:
|
|||||||
run_generators(list(machines), prompt_values=mocked_prompts)
|
run_generators(list(machines), prompt_values=mocked_prompts)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
|
os.environ["CLAN_NO_COMMIT"] = "1"
|
||||||
|
args = parse_args()
|
||||||
|
generate_test_vars(
|
||||||
|
clean=args.clean,
|
||||||
|
repo_root=args.repo_root,
|
||||||
|
test_dir=args.repo_root / args.test_dir,
|
||||||
|
check_attr=args.check_attr,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from clan_cli.generate_test_vars.cli import generate_test_vars
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.with_core
|
||||||
|
def test_generate_test_vars(
|
||||||
|
clan_core: Path,
|
||||||
|
temp_dir: Path,
|
||||||
|
) -> None:
|
||||||
|
test_dir_original = clan_core / "checks/service-dummy-test"
|
||||||
|
service_dir = temp_dir / "service-dummy-test"
|
||||||
|
shutil.copytree(test_dir_original, service_dir)
|
||||||
|
|
||||||
|
# Make the copied tree writable
|
||||||
|
subprocess.run(["chmod", "-R", "+w", str(service_dir)], check=True)
|
||||||
|
|
||||||
|
generate_test_vars(
|
||||||
|
clean=True,
|
||||||
|
repo_root=clan_core,
|
||||||
|
test_dir=service_dir,
|
||||||
|
check_attr="service-dummy-test",
|
||||||
|
)
|
||||||
@@ -9,7 +9,7 @@ from functools import cache
|
|||||||
from hashlib import sha1
|
from hashlib import sha1
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from tempfile import NamedTemporaryFile
|
from tempfile import NamedTemporaryFile
|
||||||
from typing import Any
|
from typing import TYPE_CHECKING, Any
|
||||||
|
|
||||||
from clan_lib.cmd import Log, RunOpts, run
|
from clan_lib.cmd import Log, RunOpts, run
|
||||||
from clan_lib.dirs import select_source, user_cache_dir
|
from clan_lib.dirs import select_source, user_cache_dir
|
||||||
@@ -22,6 +22,12 @@ from clan_lib.nix import (
|
|||||||
nix_test_store,
|
nix_test_store,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from clan_lib.machines.actions import (
|
||||||
|
ListOptions,
|
||||||
|
MachineResponse,
|
||||||
|
)
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@@ -1102,6 +1108,15 @@ class Flake:
|
|||||||
full_selector = f'clanInternals.machines."{system}"."{machine_name}".{selector}'
|
full_selector = f'clanInternals.machines."{system}"."{machine_name}".{selector}'
|
||||||
return self.select(full_selector)
|
return self.select(full_selector)
|
||||||
|
|
||||||
|
def list_machines(
|
||||||
|
self,
|
||||||
|
opts: "ListOptions | None" = None,
|
||||||
|
) -> "dict[str, MachineResponse]":
|
||||||
|
"""List machines of a clan"""
|
||||||
|
from clan_lib.machines.actions import list_machines # noqa: PLC0415
|
||||||
|
|
||||||
|
return list_machines(self, opts)
|
||||||
|
|
||||||
|
|
||||||
def require_flake(flake: Flake | None) -> Flake:
|
def require_flake(flake: Flake | None) -> Flake:
|
||||||
"""Require that a flake argument is provided, if not in a clan flake.
|
"""Require that a flake argument is provided, if not in a clan flake.
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ from clan_cli.vars.migration import check_can_migrate, migrate_files
|
|||||||
|
|
||||||
from clan_lib.api import API
|
from clan_lib.api import API
|
||||||
from clan_lib.errors import ClanError
|
from clan_lib.errors import ClanError
|
||||||
from clan_lib.machines.actions import list_machines
|
|
||||||
from clan_lib.machines.machines import Machine
|
from clan_lib.machines.machines import Machine
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
@@ -39,7 +38,7 @@ def get_generators(
|
|||||||
msg = "At least one machine must be provided"
|
msg = "At least one machine must be provided"
|
||||||
raise ClanError(msg)
|
raise ClanError(msg)
|
||||||
|
|
||||||
all_machines = list_machines(machines[0].flake).keys()
|
all_machines = machines[0].flake.list_machines().keys()
|
||||||
requested_machines = [machine.name for machine in machines]
|
requested_machines = [machine.name for machine in machines]
|
||||||
|
|
||||||
all_generators_list = Generator.get_machine_generators(
|
all_generators_list = Generator.get_machine_generators(
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ let
|
|||||||
ps.argcomplete # Enables shell completions
|
ps.argcomplete # Enables shell completions
|
||||||
|
|
||||||
# uncomment web-pdb for debugging:
|
# uncomment web-pdb for debugging:
|
||||||
# (pkgs.callPackage ./python-deps.nix {}).web-pdb
|
# (pkgs.callPackage ./python-deps.nix { }).web-pdb
|
||||||
];
|
];
|
||||||
devDeps = ps: [
|
devDeps = ps: [
|
||||||
ps.ipython
|
ps.ipython
|
||||||
|
|||||||
@@ -28,6 +28,10 @@
|
|||||||
"pkgs/zerotierone"
|
"pkgs/zerotierone"
|
||||||
"pkgs/minifakeroot"
|
"pkgs/minifakeroot"
|
||||||
"pkgs/clan-cli/clan_cli/tests/flake-module.nix"
|
"pkgs/clan-cli/clan_cli/tests/flake-module.nix"
|
||||||
|
|
||||||
|
# needed for test_generate_test_vars.py
|
||||||
|
"checks/service-dummy-test"
|
||||||
|
"checks/flake-module.nix"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,9 +6,12 @@ build-backend = "setuptools.build_meta"
|
|||||||
name = "clan"
|
name = "clan"
|
||||||
description = "clan cli tool"
|
description = "clan cli tool"
|
||||||
dynamic = ["version"]
|
dynamic = ["version"]
|
||||||
scripts = { clan = "clan_cli.cli:main" }
|
|
||||||
license = { text = "MIT" }
|
license = { text = "MIT" }
|
||||||
|
|
||||||
|
[project.scripts]
|
||||||
|
clan = "clan_cli.cli:main"
|
||||||
|
clan-generate-test-vars = "clan_cli.generate_test_vars.cli:main"
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
Homepage = "https://clan.lol/"
|
Homepage = "https://clan.lol/"
|
||||||
Documentation = "https://docs.clan.lol/"
|
Documentation = "https://docs.clan.lol/"
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
./clan-vm-manager/flake-module.nix
|
./clan-vm-manager/flake-module.nix
|
||||||
./installer/flake-module.nix
|
./installer/flake-module.nix
|
||||||
./icon-update/flake-module.nix
|
./icon-update/flake-module.nix
|
||||||
./generate-test-vars/flake-module.nix
|
|
||||||
./clan-core-flake/flake-module.nix
|
./clan-core-flake/flake-module.nix
|
||||||
./clan-app/flake-module.nix
|
./clan-app/flake-module.nix
|
||||||
./testing/flake-module.nix
|
./testing/flake-module.nix
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
buildPythonApplication,
|
|
||||||
python,
|
|
||||||
clan-cli,
|
|
||||||
}:
|
|
||||||
buildPythonApplication {
|
|
||||||
name = "generate-test-vars";
|
|
||||||
src = ./.;
|
|
||||||
format = "pyproject";
|
|
||||||
dependencies = [ (python.pkgs.toPythonModule clan-cli) ];
|
|
||||||
nativeBuildInputs = [
|
|
||||||
(python.withPackages (ps: [ ps.setuptools ]))
|
|
||||||
];
|
|
||||||
checkPhase = ''
|
|
||||||
runHook preCheck
|
|
||||||
$out/bin/generate-test-vars --help
|
|
||||||
runHook preCheck
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
{ ... }:
|
|
||||||
{
|
|
||||||
perSystem =
|
|
||||||
{
|
|
||||||
config,
|
|
||||||
pkgs,
|
|
||||||
self',
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
{
|
|
||||||
devShells.vars-generator = pkgs.callPackage ./shell.nix {
|
|
||||||
inherit (self'.packages) generate-test-vars;
|
|
||||||
};
|
|
||||||
|
|
||||||
packages.generate-test-vars = pkgs.python3.pkgs.callPackage ./default.nix {
|
|
||||||
inherit (config.packages) clan-cli;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
[build-system]
|
|
||||||
requires = ["setuptools"]
|
|
||||||
build-backend = "setuptools.build_meta"
|
|
||||||
|
|
||||||
|
|
||||||
[project]
|
|
||||||
name = "generate-test-vars"
|
|
||||||
description = "vars generate"
|
|
||||||
dynamic = ["version"]
|
|
||||||
scripts = { generate-test-vars = "generate_test_vars.cli:main" }
|
|
||||||
|
|
||||||
[project.urls]
|
|
||||||
Homepage = "https://clan.lol/"
|
|
||||||
Documentation = "https://docs.clan.lol/"
|
|
||||||
Repository = "https://git.clan.lol/clan/clan-core"
|
|
||||||
|
|
||||||
[tool.setuptools.packages.find]
|
|
||||||
exclude = ["result", "**/__pycache__"]
|
|
||||||
|
|
||||||
[tool.pytest.ini_options]
|
|
||||||
testpaths = "tests"
|
|
||||||
faulthandler_timeout = 60
|
|
||||||
log_level = "DEBUG"
|
|
||||||
log_format = "%(levelname)s: %(message)s\n %(pathname)s:%(lineno)d::%(funcName)s"
|
|
||||||
addopts = "--durations 5 --color=yes --new-first" # Add --pdb for debugging
|
|
||||||
norecursedirs = "tests/helpers"
|
|
||||||
|
|
||||||
[tool.mypy]
|
|
||||||
python_version = "3.13"
|
|
||||||
warn_redundant_casts = true
|
|
||||||
disallow_untyped_calls = true
|
|
||||||
disallow_untyped_defs = true
|
|
||||||
no_implicit_optional = true
|
|
||||||
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
{ pkgs, generate-test-vars }:
|
|
||||||
pkgs.mkShell {
|
|
||||||
inputsFrom = [
|
|
||||||
generate-test-vars
|
|
||||||
];
|
|
||||||
# packages = with pkgs; [ python3 ];
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
# Test that we can generate vars
|
|
||||||
{
|
|
||||||
vars.generators = {
|
|
||||||
test_generator_1 = {
|
|
||||||
files.hello = {
|
|
||||||
secret = false;
|
|
||||||
};
|
|
||||||
script = ''
|
|
||||||
echo "hello world 1" > $out/hello
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
test_generator_2 = {
|
|
||||||
files.hello = {
|
|
||||||
secret = false;
|
|
||||||
};
|
|
||||||
script = ''
|
|
||||||
echo "hello world 2" > $out/hello
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user