Skip to content

Commit c05fcb7

Browse files
authored
Merge pull request timfeirg#39 from agavemindlab/dev-38-builds-schema-defaults
- Apply BuildSchema defaults (workdir, script) for builds: (plural) config - Derive defaults dynamically from BuildSchema.model_fields to prevent drift - 1 new regression test Reviews: APPROVED by gl-swe (2 rounds) Fixes: timfeirg#38
2 parents 6f2cd1b + d5bd222 commit c05fcb7

2 files changed

Lines changed: 44 additions & 1 deletion

File tree

lain_cli/utils.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1142,7 +1142,26 @@ def tell_builds():
11421142
if has_build and has_builds:
11431143
error("cannot define both 'build' and 'builds' in values.yaml", exit=1)
11441144
if has_builds:
1145-
return dict(getattr(values, "builds"))
1145+
from pydantic.fields import PydanticUndefined
1146+
1147+
from lain_cli.schemas import BuildSchema
1148+
1149+
result = {}
1150+
for name, bc in getattr(values, "builds").items():
1151+
bc = dict(bc)
1152+
# Apply BuildSchema defaults for fields that have defaults
1153+
for field_name, field_info in BuildSchema.model_fields.items():
1154+
if field_name in bc:
1155+
continue
1156+
if field_info.default_factory is not None:
1157+
bc[field_name] = field_info.default_factory()
1158+
elif (
1159+
field_info.default is not PydanticUndefined
1160+
and field_info.default is not None
1161+
):
1162+
bc[field_name] = field_info.default
1163+
result[name] = bc
1164+
return result
11461165
if has_build:
11471166
build_clause = values.build.model_dump(
11481167
mode="python", by_alias=True, exclude_none=True

tests/test_multi_build.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
from lain_cli.utils import (
88
DEFAULT_BUILD_NAME,
9+
DEFAULT_WORKDIR,
910
context,
1011
make_image_str,
1112
tell_build_deps,
@@ -716,3 +717,26 @@ def test_image_repos_no_build():
716717
yadu(values, DUMMY_VALUES_PATH)
717718
res = run(lain, args=["image-repos"])
718719
assert DUMMY_APPNAME in res.output.strip()
720+
721+
722+
@pytest.mark.usefixtures("dummy_helm_chart")
723+
def test_builds_plural_applies_schema_defaults():
724+
"""builds: (plural) should apply BuildSchema defaults like workdir."""
725+
values = load_dummy_values()
726+
del values["build"]
727+
# Omit workdir — BuildSchema should default it to /lain/app
728+
values["builds"] = {
729+
"default": {"base": "python:3.12", "script": ["echo ok"]},
730+
"gpu": {"base": "nvidia/cuda:12.6", "script": ["echo gpu"]},
731+
}
732+
yadu(values, DUMMY_VALUES_PATH)
733+
734+
def check_defaults():
735+
builds = tell_builds()
736+
for name, bc in builds.items():
737+
assert bc.get("workdir") == DEFAULT_WORKDIR, (
738+
f"build '{name}' missing workdir default"
739+
)
740+
assert bc.get("script") is not None
741+
742+
run_under_click_context(check_defaults)

0 commit comments

Comments
 (0)