From 3782777058a8af789bef00b366680313bf30d1de Mon Sep 17 00:00:00 2001 From: Lukas Greve Date: Wed, 25 Mar 2026 09:34:00 +0100 Subject: [PATCH] refactor: functional separation with deploy/, recipe-generator/, and bin/ - deploy/: deployment bash scripts (4 files) - recipe-generator/: recipe generation tool (Python + YAML configs) - bin/: executable wrappers (single generate-recipe entry point) - Updated deploy.sh, README.md, DEVELOPMENT.md, DEVELOPMENT_QUICK.md - Updated tests/test_recipe_generator.py and tests/integration/test_integration.py - Updated CI workflow and Makefile paths - All 41 tests pass --- .gitea/workflows/test-generation.yaml | 10 +++--- DEVELOPMENT.md | 34 +++++++++--------- DEVELOPMENT_QUICK.md | 12 +++---- README.md | 2 +- bin/generate-recipe | 2 ++ deploy.sh | 8 ++--- {scripts => deploy}/core-count.sh | 0 {scripts => deploy}/deploy-distro.sh | 0 .../install-prerequisites-on-linux.sh | 0 {scripts => deploy}/system-memory.sh | 0 {scripts => recipe-generator}/Makefile | 6 ++-- .../generate_recipe.cpython-314.pyc | Bin 32716 -> 32631 bytes .../generate_recipe.py | 10 +++--- .../python-update-package-names.py | 0 .../recipe_templates.yaml | 0 .../recipes_manifest.yaml | 0 .../requirements.txt | 0 ...ipe_generator.cpython-314-pytest-8.4.2.pyc | Bin 54981 -> 55121 bytes ...est_fragments.cpython-314-pytest-8.4.2.pyc | Bin 18187 -> 0 bytes ...olden_masters.cpython-314-pytest-8.4.2.pyc | Bin 21373 -> 0 bytes ...t_integration.cpython-314-pytest-8.4.2.pyc | Bin 14218 -> 14239 bytes ...e_composition.cpython-314-pytest-8.4.2.pyc | Bin 54708 -> 0 bytes ...ic_validation.cpython-314-pytest-8.4.2.pyc | Bin 24491 -> 0 bytes tests/integration/test_integration.py | 10 +++--- tests/test_recipe_generator.py | 12 ++++--- 25 files changed, 55 insertions(+), 51 deletions(-) create mode 100755 bin/generate-recipe rename {scripts => deploy}/core-count.sh (100%) rename {scripts => deploy}/deploy-distro.sh (100%) rename {scripts => deploy}/install-prerequisites-on-linux.sh (100%) rename {scripts => deploy}/system-memory.sh (100%) rename {scripts => recipe-generator}/Makefile (87%) rename {scripts => recipe-generator}/__pycache__/generate_recipe.cpython-314.pyc (66%) rename {scripts => recipe-generator}/generate_recipe.py (98%) mode change 100644 => 100755 rename {ingredients => recipe-generator}/python-update-package-names.py (100%) rename {scripts => recipe-generator}/recipe_templates.yaml (100%) rename {scripts => recipe-generator}/recipes_manifest.yaml (100%) rename {scripts => recipe-generator}/requirements.txt (100%) delete mode 100644 tests/integration/__pycache__/test_fragments.cpython-314-pytest-8.4.2.pyc delete mode 100644 tests/integration/__pycache__/test_golden_masters.cpython-314-pytest-8.4.2.pyc delete mode 100644 tests/integration/__pycache__/test_recipe_composition.cpython-314-pytest-8.4.2.pyc delete mode 100644 tests/integration/__pycache__/test_semantic_validation.cpython-314-pytest-8.4.2.pyc diff --git a/.gitea/workflows/test-generation.yaml b/.gitea/workflows/test-generation.yaml index 37dda99..d02ac8a 100644 --- a/.gitea/workflows/test-generation.yaml +++ b/.gitea/workflows/test-generation.yaml @@ -3,13 +3,13 @@ name: test-generation on: push: paths: - - 'scripts/**/*.py' - - 'scripts/**/*.yaml' + - 'recipe-generator/**/*.py' + - 'recipe-generator/**/*.yaml' - 'fragments/**/*.ks' pull_request: paths: - - 'scripts/**/*.py' - - 'scripts/**/*.yaml' + - 'recipe-generator/**/*.py' + - 'recipe-generator/**/*.yaml' jobs: generate: @@ -28,7 +28,7 @@ jobs: - name: Generate all variants run: | - cd scripts + cd recipe-generator python3 generate_recipe.py \ --manifest recipes_manifest.yaml \ --output-dir ../recipes/ diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index aa5ce02..2f4a4b4 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -21,7 +21,7 @@ Phyllome OS uses a **fragment-driven** kickstart generation system: ``` fragments/ (54 .ks files) ↓ (modular snippets) -scripts/generate_recipe.py +recipe-generator/generate_recipe.py ↓ (YAML templates + manifest) recipes/ (16 auto-generated .cfg) ↓ (ksflatten) @@ -40,14 +40,16 @@ VMs and ISO images | `recipes/` | Generated recipes | Manifest-driven compositions | | `dishes/` | Flattened kickstarts | Ready-to-deploy artifacts | | `ingredients/` | Legacy building blocks | 35 `.cfg` files (legacy) | -| `scripts/` | Automation tools | `generate_recipe.py`, Makefile | +| `recipe-generator/` | Recipe generation | `generate_recipe.py`, YAML configs, Makefile | +| `deploy/` | Deployment scripts | Bash automation tools | +| `bin/` | Executables | Wrapper scripts (e.g., `generate-recipe`) | ### Data Flow 1. **Fragments** (`fragments/**/*.ks`) - Small, reusable kickstart snippets -2. **Templates** (`scripts/recipe_templates.yaml`) - Define recipe structures -3. **Manifest** (`scripts/recipes_manifest.yaml`) - Specify variants (version, desktop, storage, etc.) -4. **Generator** (`scripts/generate_recipe.py`) - Composes fragments via `%ksappend` directives +2. **Templates** (`recipe-generator/recipe_templates.yaml`) - Define recipe structures +3. **Manifest** (`recipe-generator/recipes_manifest.yaml`) - Specify variants (version, desktop, storage, etc.) +4. **Generator** (`recipe-generator/generate_recipe.py`) - Composes fragments via `%ksappend` directives 5. **Recipes** (`recipes/*.cfg`) - Generated kickstart files with fragment references 6. **Flattening** (`ksflatten`) - Resolves `%ksappend` into single dish file 7. **Deployment** (`virt-install`) - Creates VMs from dish files @@ -169,7 +171,7 @@ EOF ### Fragment Validation Script -Create `scripts/validate-fragment.sh`: +Create `deploy/validate-fragment.sh`: ```bash #!/bin/bash @@ -205,7 +207,7 @@ Recipes are generated from templates and the manifest file. This section covers ### Manifest Editing -**File:** `scripts/recipes_manifest.yaml` +**File:** `recipe-generator/recipes_manifest.yaml` The manifest defines all recipe variants using modifiers from templates. @@ -252,7 +254,7 @@ recipes: ### Template Editing -**File:** `scripts/recipe_templates.yaml` +**File:** `recipe-generator/recipe_templates.yaml` Templates define the structure and fragment composition for each recipe type. @@ -551,7 +553,7 @@ done **File:** `.gitea/workflows/test-generation.yaml` **Triggers:** -- Push to `scripts/**/*.py` or `scripts/**/*.yaml` +- Push to `recipe-generator/**/*.py` or `recipe-generator/**/*.yaml` - Pull request with script changes **Steps:** @@ -609,12 +611,12 @@ luanti EOF # Step 2: Add to recipe template -# Edit scripts/recipe_templates.yaml +# Edit recipe-generator/recipe_templates.yaml # Add to 'required' section: # - luanti: fragments/shared/packages/luanti.ks # Step 3: Regenerate recipes -cd scripts +cd recipe-generator make generate-recipes # Step 4: Validate @@ -637,12 +639,12 @@ plasma-workspace EOF # Step 2: Add to template -# Edit scripts/recipe_templates.yaml +# Edit recipe-generator/recipe_templates.yaml # Add to optional/desktop section: # kde: fragments/shared/desktop/kde/packages.ks # Step 3: Add variant to manifest -# Edit scripts/recipes_manifest.yaml +# Edit recipe-generator/recipes_manifest.yaml # Add variant: # - version: 43 # desktop: kde @@ -660,7 +662,7 @@ make test ```bash # Step 1: Add template to recipe_templates.yaml -cat >> scripts/recipe_templates.yaml << 'EOF' +cat >> recipe-generator/recipe_templates.yaml << 'EOF' minimal-server: description: "A minimal server recipe" @@ -681,7 +683,7 @@ cat >> scripts/recipe_templates.yaml << 'EOF' EOF # Step 2: Add variant to recipes_manifest.yaml -cat >> scripts/recipes_manifest.yaml << 'EOF' +cat >> recipe-generator/recipes_manifest.yaml << 'EOF' - name: minimal-server variants: @@ -729,7 +731,7 @@ luanti %end ``` -**Template:** `scripts/recipe_templates.yaml` +**Template:** `recipe-generator/recipe_templates.yaml` ```yaml templates: virtual-desktop: diff --git a/DEVELOPMENT_QUICK.md b/DEVELOPMENT_QUICK.md index d856610..c6a3df8 100644 --- a/DEVELOPMENT_QUICK.md +++ b/DEVELOPMENT_QUICK.md @@ -10,7 +10,7 @@ sudo dnf install qemu libvirt virt-install pykickstart pip install PyYAML pytest # Verify setup -cd scripts && make generate-recipes && make test +cd recipe-generator && make generate-recipes && make test ``` ## Core Workflows @@ -28,17 +28,17 @@ new-package ### Add to Recipe ```bash -# Edit scripts/recipe_templates.yaml to include fragment -# Edit scripts/recipes_manifest.yaml to add variant +# Edit recipe-generator/recipe_templates.yaml to include fragment +# Edit recipe-generator/recipes_manifest.yaml to add variant # Regenerate -cd scripts && make generate-recipes && make validate-recipes +cd recipe-generator && make generate-recipes && make validate-recipes ``` ### Run Tests ```bash -cd scripts +cd recipe-generator make test # All tests make test-integration # Integration only make test-container # Containerized @@ -60,7 +60,7 @@ done ## Architecture ``` -fragments/ (54 .ks) → generate_recipe.py → recipes/ (16 .cfg) → ksflatten → dishes/ (28 .cfg) +fragments/ (54 .ks) → recipe-generator/generate_recipe.py → recipes/ (16 .cfg) → ksflatten → dishes/ (28 .cfg) ``` See `DEVELOPMENT.md` Section 1 for detailed architecture overview. diff --git a/README.md b/README.md index 7652bec..1d61d03 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ chmod +x deploy-vm.sh ``` ./deploy-vm.sh -Executing: ./scripts/core-count.sh +Executing: ./deploy/core-count.sh System has more than 2 core (nproc --all: 6). [...] 10. virtual-desktop-hypervisor diff --git a/bin/generate-recipe b/bin/generate-recipe new file mode 100755 index 0000000..8a6cca7 --- /dev/null +++ b/bin/generate-recipe @@ -0,0 +1,2 @@ +#!/bin/bash +exec "$(dirname "$0")/../recipe-generator/generate_recipe.py" "$@" diff --git a/deploy.sh b/deploy.sh index bbd5ab7..c1e80f1 100755 --- a/deploy.sh +++ b/deploy.sh @@ -13,10 +13,10 @@ execute_script() { # Array of scripts scripts=( - "./scripts/install-prerequisites-on-linux.sh" - "./scripts/core-count.sh" - "./scripts/system-memory.sh" - "./scripts/deploy-distro.sh" + "./deploy/install-prerequisites-on-linux.sh" + "./deploy/core-count.sh" + "./deploy/system-memory.sh" + "./deploy/deploy-distro.sh" ) # Iterate through the scripts and execute them diff --git a/scripts/core-count.sh b/deploy/core-count.sh similarity index 100% rename from scripts/core-count.sh rename to deploy/core-count.sh diff --git a/scripts/deploy-distro.sh b/deploy/deploy-distro.sh similarity index 100% rename from scripts/deploy-distro.sh rename to deploy/deploy-distro.sh diff --git a/scripts/install-prerequisites-on-linux.sh b/deploy/install-prerequisites-on-linux.sh similarity index 100% rename from scripts/install-prerequisites-on-linux.sh rename to deploy/install-prerequisites-on-linux.sh diff --git a/scripts/system-memory.sh b/deploy/system-memory.sh similarity index 100% rename from scripts/system-memory.sh rename to deploy/system-memory.sh diff --git a/scripts/Makefile b/recipe-generator/Makefile similarity index 87% rename from scripts/Makefile rename to recipe-generator/Makefile index ec1a690..bfdce20 100644 --- a/scripts/Makefile +++ b/recipe-generator/Makefile @@ -25,13 +25,13 @@ validate-recipes: --validate ../recipes/*.cfg test: - python3 -m pytest tests/ -v --tb=short + python3 -m pytest ../tests/ -v --tb=short test-integration: - python3 -m pytest tests/integration/ -v --tb=short + python3 -m pytest ../tests/integration/ -v --tb=short test-container: - podman build -t phyllo/test-runner tests/container/ + podman build -t phyllo/test-runner ../tests/container/ podman run --rm -v .:/phyllomeos:ro phyllo/test-runner clean: diff --git a/scripts/__pycache__/generate_recipe.cpython-314.pyc b/recipe-generator/__pycache__/generate_recipe.cpython-314.pyc similarity index 66% rename from scripts/__pycache__/generate_recipe.cpython-314.pyc rename to recipe-generator/__pycache__/generate_recipe.cpython-314.pyc index 0121269513c542e72b23afb79921a476060afe6d..39877538ec7eeccc5794e45bdbbe29e5617546d2 100644 GIT binary patch delta 2379 zcmaKt4RBOf702J%w{JhQ$!1ANQUYv9NV1SkfD&S|X_8Gtg_yLMk`IPTSax5Mmyg}e z-Q8HWLyC?vh)r91IxQm%Q?+)Qw$qY6I!ZfQX_+xn92pBDi=a}i7AOS=#c|Yn&dUfm zcHEu)?YZZk`@di3op<6>xcM(|Ezfp2B>J4(|E^Xs<4P;ghP#y#w@|}cT=fsCQB{PJ zF`*w)-Z$mR%01U5!nFAs{~d`?OMlij0`O~;9cQ3JKj$a}=)fD!8F&z1$ZB#_nS}gUMyG;0| zs~co=XDg(_LX&$>Z@h#;ATB>D^?)d$^&p* zZ!0f0{cm5qvKXGgsmc;Kj;~d|;56iT4jQ-B7l4d@z<1v4-$tIaW9djD6pyRXh*w0& zu~8t==g7zjHJLGoWAW|AzVX}D`R#lP895Y*h&Tsj&mF}b^4xFJqT$h0L``JO2~~}X z6gkBN<6*{jMjDlxM%arj?tJX6$)*(z)Pzl7*N?A!+XRo}p4GukF%Eo=kda48#<+p+ zu&<7x5$JS{yLg#{ELtLw;z>s}dIrABG0(GKrsZUmct|7@Vm*5&u&j1HO%<&j12+#f zj$bsh^@?%lOZD8k7iH+gHyc`E2>;p83{T=cfePpC=tCF_w8Cb5J+K8Ryzw+xUb-!? zPWLpWc^^|PD@f)?EhVm3sW+n}l0u7%7+z^9TEQFgIdAVk9O4igFTX#U8WS@{(-;v~ zBSOd8;3{|vhk`Y*PTvb6SGuXFwEp6}M+IKA9;HYmJo8O^7cHad#5N07IV-;$AG!#~i9GJU&(c(~&s2Nf!#THSQu zU7g>8S^bU9yF*b>a=&wMsQ?yDfh=y71^w5&RL)4K=_YaK2Wx_yUW%@7>Vtjm4ANn3fJD zwOBN*`2BTt_&wu1 z<2U&ISO;7{bA0O28|>h6n6XWSMzsiCpLl?qW}${6Mn+J{NUCFV*TR$7a6^bT~a4;n9VqY(=lU>i0%C%6%`+G%Q2TD{gfja z<;y~&M5AtbGE*4zTG(@|qfg(HIA?ow z;k@Bhrr8y_!;7pxg;o zkZ+GUEFY9wiGNz+iMf?ai=4wX&PzT!DO_6BJhDc)Tno&4=cvPe#cU>>D-N0I3fiMp za_PrK9{T&Z3Yh-Y(F*x$g+lh#T4&7a`o!&wm7sOU49wz@9aH)Bv{CU1A4UON#v5@1 zZl0_T%(AnRv5di|A}+JFlHdcuBNOzKT8zxi*c$0|nHp7_L?a%XJiokGfy(O=^Uq1g gHW}R4+O3i~Yj^sTTy)lK+jZY{Su)=x?k0tQ1C+yxCIA2c delta 2410 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 delta 6529 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 A{Qv*} diff --git a/tests/integration/__pycache__/test_fragments.cpython-314-pytest-8.4.2.pyc b/tests/integration/__pycache__/test_fragments.cpython-314-pytest-8.4.2.pyc deleted file mode 100644 index bae80558bf4bba6a66790a2286f9debc39bd3f3d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18187 zcmeHPeQX=&dA}nm^2nn^iIOZ?*2l@REYq<*EGhoBY*` z+n(pXNl~)h)F?9SK)v^VJnwVw-Fxrv`FNkxGew0i3XWg?=MTewRYOtZSkMl;nprzQ zQ`7>*Q*r7%#nY$gxJ5o&2W+#JI%=RGZm&~X9B~Jg!z!i(MD|T9xwz{197uk^= zMlUVL+jc^hFQ}m6rMw-|GTs4cInO}4g?B<)!Mh->xzfg2v>ro!V>VmwIV91+ID zF+pq@^3jrQBpAOaImB@ij>SdEHS)sP!0^yW_t?O=dPnk@9gtcn%C`1HV{p=P z^%T$gZ5=f4e!jiK(rHubc?)knC%7ed^Gwh|`7(}D=~VKLs4aO~dQy1Qjcl&rD&HmOJ>3XDf* zBXO*3m%JK_fYvG|ynPzmV4Ry4f?}LYc=bz&dti0VMnYVo*wqyjMFAF7Xlh8=j7bBcf!Vjsk@!RR+Y1(b?&cOd3Ew!RbIGI3q~TfEb(* zkOOc79GD3LXL*=2;-pm6EoT8K`Ur^qWq%*6G=)pxD|I4GFE6!zA7s zQ^6`Kw#o?B8ji$;Ng|I&t}*7PB{nZrDh~`El`%AV(g`eU3YW6D8{lSvy0>*((zfLj zJGEu&pO#&p$<(%`YTMr4x?FpBdFzqo@}mnw_t>o|w)InrE*PW#OHS{e7)_lR{ltnj zi(N{~n$mJ+^vC{B<%XXr6^BPthez*ckt!YTo*wGnNek^3NIy9hkblBbzE&#YS!S9QR6zQLjkc=M*V#<>iel; zs*mn30gRvl>5)9=h*^00QoG-JV8D#&llNu3)aA*Dir41OCPZ(@L3ACP@=Jm|h;Cd- zmj=eQ09|x>l!NF-zr3=;=%*n1xku6KC=1yCC|X_0v|6)J)7&$!d;&D4NAgG@MCf*% z>tmpEsrHOaV=dF_jPpk5e3*_|4%4Kkj~;|xPO6qt(R!B&t@WkKT?}3pH~?k<>bMXQ z0gYM`RwxrxAS6a3BnTXc)6YJ1_G<{AsOCaZ!1zcso`+8kDDPK5dA|(GM-h};5R?Il zT`#E_P621Y=@xNzVj?`}y2>3@>YfF_W+l5)O>hE;2NQhY1Xcn?P(%`Zb_5@mWJ3fd zDCr1_HULtmb}u5~uzD*bX4vdB7qVb;pBY0BC>Sb3C`YQ1NmCvO#OE52mBE1iWC==U zysTI*BjQJ8HH*xur{cAjuf2SqqMg0;jYjR9@-zWVKovk0q<7nUQtdqegpgl+S!n?v z#FnEy?;sFD7VrZrp6N+F(*sC^q;m?XlHNVk^9}-`sX^soYEYSftne}#ZZw)%DZ^Ao zrEpv=s<_U4yYQQZufLq!c_QiVQO0EMq>itxC)JkK3J3~ATC-B+wFLG4Ebv1SCxc%R zEL~7}(L4d*lh5#~`z;&5n7-(BaA`*PgGH(X8E{sQ5vP_j&gZE|^ES+lZ8$RPse%D} z%qp8jwo{G)CT5fK1(0{f3go=~lxu*E*$3P)M;(Pw-roU0&iI*p=8XobG3PewthJsx zYlFW6O&Qb9F_+&p(qN2S%lVxeMIANxtO^ETuyE8l-7vFLA;?!#b<{b0m*pd$@dbjx zVQ{OVo;x3=4qI!eFwIeC9cS$w7U0y5oMNnr(+-uT=>(jZF=k|^sY=ZPR6564voc#p z)xdnm*kkPAAA>S0=fbphWuGh2>R0S7K~_Tb70z7=$1ifRdBfNO1rGGXmLY;h5*S>b zLCp>ukz1gOoe53}0FnrTP%P-}^Y=aHvq(icsj8^yWx1N+7y=@wh;dLLg;1in zKM1ODh>J%#c@$j2a)|SlNmg-Qlq^xuBqs&H-pi6LhDM+rdV(e^c}*N!l;M*W7`#+! zZn&(Bm$X6)X~X8MegdkNBH4?rFgpNvr)FYN5?AiTuBf|`O`HnHBqtGqp+FqqN~*xD zew+OyIx`w4;mD+9n}B;EICnlb!Ieee?WG95r}E&8aTwQ>;Z|~tM?sGSW#6vci$n_| zig!gBHN)vH8BR?%37U8$AomKOO0Lf`>4p9r{E6>FvOxW-t>^<=;e9*BxL%$A{rT6c zGmhFNN9`)ZzQ$Z*Uh`b@T&J(MfBWFK4&FGoysiBX({bNsFWCDbv+qNu<3pzTE^~T~ z0T2RE_Eu%QJ5t^q%if)fj{A0-vzvaue8+cw`|a}O#{J9X2NwHR-QJ9Qcgnr{=Kd9T z$66uu`}rph%3XoF<=&q#MX#}6VUuO8D@+?|g?oQ_zlb}*HtUQ)+A764G|0M!zH~moD4R`l$QPqhC>fNro9+%~Z z4fQ<^>w9(@QZsjC7PfBBOMEYTd}ys3#jYq1JIy zrv|+NB!Hb~(d`fd4W}B6=$LJAoT3H=3R@fp&VoY%?!1~Bi~!=mJq{8DIsG=BkJA1< zaJlGCk&(PAF3*6x$)m&~(iuu2pz}YOR5f>^)1<03aw1rN07;^vV}TJlei4=;*C>GH z3m6j@(D5X;NVKb8q8k%TV>mKCJsT1d&c-P*7>fbj*h3qVlkITdiE>~hafIY<|;K*3=}HzZQQbT}f2l3TrUAPPf7J3JytjLa=2gw|_W3M}Z0KOk#Z z+S3SVyznl+02jeAh(CY?U_n;1vR3qJamAa3Zxmh+Ef+T|7Tl|-UUYv@wso<0wPM?w zi8m5|^t+1#pqFJl+f$zHH##z&rX^3)+e}8*TyCGvv<)w{4JXh3PUh@X>g-f<`by^P z+|t>()zWRrx-)l5yef_zQtyI|%eXnHeb^l69!)o1*ue(16l&Jc&jB;0AJEAWC z>%JQUe}3jWXKoxzwx3K^4y?FOt<~pMgzyD}7tgl#FY;1u1HFER1`7~Xh>u_i;*#BL zNn8EaM=WXEIaK=P!*4rJ^OpUpwFFoAK1E%D67lC>$ofKe_#N6Z302C=&5=*J%Cqp5 zMYRu>Vg4TL7Jo?TF)a6heD0x*Y2A1>p*>IS(N!agLa$tmdHxlI3l$Xp5Ei|@)blNE zu*)nXXrSaAu;lH22CYGV0i;a3?puT9|JTa$AN)5J2AmC)k4@}XVL*T9!Q6^8#kpBg z;6mV462@Wihgyj+6TJ)z8QfGe!AMAKA^mV|)L`T_DbWq&BveRLq6)i;roLJqt|{Sa z;?Tzii;zn+v~WEDIN^{$xS25eegxEBg41z)M54sWr>0h5kGPp=bbf zwE#Sofbl@VDXBb25&#YeCSnSb1?qv#?zJzRUMtR{BV;4WN3~5i3*P=hrgs0eA%GGC zRX(*-W!2Z`GIi~#y7sp_GIjfx>h`~1TnS1`ab-5%D7CxWzhC=SZN_(S$#?MeU2nF$ z(X#B_eq-;7xA7KP>{<1AS3KNLinqMUew|&dsC)D38&_YCCL534w%(e(efmdpKl&0_ zYA?_SAT2-mGpn`4yH-Qh9awYbg&2HdusCdMLk_%OKWNiV${b0sQKTk8pv!KqEB|21fPIcKdi?CxFo(PZY`4B{mC1HKzRAOK+ zFpgV!3D=|$f&JF;=FSeu2Ahh}gh#6(!7CR*SxZ#)cXmKnK`g3sng{(&6v144*ps_O zs<_=@uT*urZ{UfS_wq#7)m=WS#TOFg^F;Oxh zgrX$aJOg`};Gcs1hJ;roFxPQ-KMD|X>QtGN$doSMdgy%p^ahFE*@K>?@SP{p8(OFg6ny0;UZ`LYRQxK-o(mKFn>yWCD{(NJP{&G#yk?K^tWiRDA~m z+B;x4wP3pd?v#YFH~#&PZ0+6iR9{b|J-(aIr9B63?Mr*Q7Y0^Kxf_SlrOnB>4oR+v8AsayLK#TJG6LgnXQKN3R|7A9fDu77So(x8VC>QbxTHR1vw}Ucc8Dv zL??xgt87Jvtxd7DN!y7eTf5A1kXd25jO_&clG`!O`K4_q7LVw4OGar$W}&p)!Mw^v zr-h!NB!h)r)0XzOEex)1*`91XnBH=5VfY@qCBxRF*qWrRC&|_LsJJBC}9h?qFW!qSHcV{iX=2in5~K4(X#5^>vDQmg2syHA`(@*IHm! zAJ(fE%|wP`E6X{+1Z+QQ?{^D%*34vSHe zC=5r!@o;duSrp>4v4nea7UGVYp)0s@(H9Eixd3;U(43^r5L6gURE;Xb)rO>t_d^^R z2Xa+FLo@7`fG5_0b+Ul=xyVH<;4H~IhRs1>!HmpI9SHHUM?!mg`KK;co0pGrm=(Tqzt%GtGM8V4B&Z z7mlQvR=u!s%ds@mu9J18nZ0@;>pEElB)ebXF10TVu2oazoW4DuWQG=BUiNTs28TJON7t>nzq|U*)mzczcC5(xrJ>K9UbkeFR*;#}a0l3E{B%;t;AS|t9`|)0@P7mD z2OSGk3&j@=qZb%33u1!q%czy>h{__Ine^a{gdf$6#VcImkY7W(+uw^*6U+7Bl^>?--~I6fBZNzEXSR) zrWtnU%R(4K@o)1Y%_xd-#k-1`17Pz zLT`uokp*gu>IYeKsbtiGipU(b01+>PtU6?>fqK>&rr)B6-lE>JN|u&3avrGU9YGP< z?c^2|>ES$rcI{k@bV++;L4tQ@GLYn`s+J>4_-$8^kmtt1>GrC!JA#-=JYmaQmcSi+y3}lOn2W*J9yn zW#dgIUD@{bzI5fmTW8Xhr=ZSLo$)lJJPk=^Bz0htip)uAxr2F?nNABm?|JJoUSG=VTlPM)==ex}ahAPv7~|GYe@%op zY1yNeRy=bUz0ptK?d(f+_F;rZKMliPj3#S(lkPqYdh4e#=&hf|5IP_{*7we3r5fYk zprW}i)vWgXny8Q}>D?oJ@0?OtY7H2l2VIN?7)%y-Q;SD!QQ9GZ8hf_)rP{MbrQ8+7 zt5ogUM89yuYC-*ihh5+ni>_aMs_GY679^i#G4k0K;?vhQHQo_hV}t@Ld#W8zoOg+bA;4uqS7Ri=SwQe{g6NLw1~s50H?ozKk>VYY)31;91QIH1=cD%e&*w%s`lgx z`P1pj{vXw(EB#rLeoT|}W3r?l%P?a}U+?V~Zx1J%u#odhGh-;})#@dqv;zG+4NA)$ z%!8!Q>I^+|B|Xl~vUeC|;(#pahnGESX~i>)l74``yYFOb-$@k91Dd4oPr6T{NFR_T z{eUd#fw24JyIYiMl=M*1dNS3j_EZGA*5Pi~$#=pEORWJVJ#;Y|lHOsIcZHIE&nA-oyAZ}B`w>cYKZ2$Iz5n+kdf5?vzbMUT9i+%?h zbeF!VJ(J0Q&at?4+Z@Q$0|Ii&{7&#elt2Hf=}WRl>oJUG-}7$%$@~b97r3KuBWri_ zn4TiNANmb)zST8{=AfOKbD-ZGV*WPPVT%2(oUe4*C-4!m+7r{xs*mUzU-JKRhoNEq z&pvnF4fW5bG&aEA z$SLTGANlRYq(gSiBehZRK^A(XW_20j@@i!6nWkI)s^t7%pvNzr*iOO`Nvs-t|~y%!=Gz?p;o zm=63}@KM2h$1J^53xU({#{Fa%4#mh=IZDjT46{Oco zOIanLzwzRY;bh0jj{P~X9ng8vnuS4j@FPT8x&cxcIiyLr>$3j`+K^vRXP1OoVP7T`)4f{kBSv7@1=O=ufs6!~e6972y8`P^TEU diff --git a/tests/integration/__pycache__/test_golden_masters.cpython-314-pytest-8.4.2.pyc b/tests/integration/__pycache__/test_golden_masters.cpython-314-pytest-8.4.2.pyc deleted file mode 100644 index 944c7d17f97544cd4d03b642e862f510bb7143bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21373 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 diff --git a/tests/integration/__pycache__/test_integration.cpython-314-pytest-8.4.2.pyc b/tests/integration/__pycache__/test_integration.cpython-314-pytest-8.4.2.pyc index 92d53bfce5b13b35504d53e368f06cf33269cbfb..a2d8b7250013a1e7333edb60a0aa0619542f193a 100644 GIT binary patch delta 894 zcmYk4O-vI(6vua@DU@zYX-i7W+Lj{N<-@jt0#QU8s8ADHSc~3VR~T?(zkIVKz(wQ5 z#DgJ@M-sgm5@SMo^l0MA0|z*`Hxm!u^x)YzuNcB4`^$gcyf<%V{`<22w(cGAdO9UB zR`)-fo${e~kN9_eK-bI$9owWe3WimO=6f>a><()Axx#W@U&t5pTCQBu_(}U0(#iKb zzA0(3MNoWflt|Ju>4(GlV)6Onv8Vsok!bF@Djh+WSheNTo%OZ)R?Pw*_xVR2fg~_uVgE0zL7F7Nr5Dkrq zIKxB6&kacN?*Wy}H{HRXgk+k3dOlrnw2LJEu{X@W_V!=)hzWQFir`0yucLY)g1Qe8 zMku^1oOP*AKocOzm%^bz<`nw07o>!=yDiEry=pwBx@Ev7wHOrmt8jwE`C<5-=&nVg zge>qUeGg)1``ezmQn8#X2(R?{f(8mUxWs?=1!e5TgilgjT*IeC$O<1(HpD)!71JMU z8Rfa9JL$H`#JOUa6Gxy$(2qzU z&WwUAPOlL^4C_(Fdh!q)C%(?T2lX);9J_w;wkBrr4I28rud;;x-g)!R(smhXO%qNZ2(N&BJN2*?2h9A{8pR z)7W>RSRPeb#LP!f99NlI4^tS%ZJCVQby{p`H5Jn@uWGh?*D7p_kx=iAe(3<`(aQ(a z*wH!N=e9d<uT)Utrd>C`=#w7>rTilQ1AYGz=y#0!H>X;5ES3qdixX<>m?G#o9*JsM5S60cz$xQ;&bUQ&Zon?( z4C3N>sGGEkPoZbBP#W$eWJTO>-`Y4%YzLQ;iS*)XBBtSZ;Vg#l!*HHr83WqxtYKOz zaf)Gb<*rCIU9*!eQ^<3}%u~>}OQy90nwam%%3Loy%*HO~B?PZ%i_2GIiS(M2pgI)H zG9!jZj!1(z6&)gzVkFwVzV76u`*PY7L45-&2y$R4y6n)0foKFwb8$BGA2?} zArcXLQ{#7?;!-k_U0XExP0QQ{9FntIyM~n+w4pJO(vtDmQd-xN$+WX=m_;{i8IlP6 zuONnqBQ(UG#GwnuPqDUDHvY5`J?1i_(AK7aP-yZoKgi DiZJZV diff --git a/tests/integration/__pycache__/test_recipe_composition.cpython-314-pytest-8.4.2.pyc b/tests/integration/__pycache__/test_recipe_composition.cpython-314-pytest-8.4.2.pyc deleted file mode 100644 index 7890c022357dc0aac0f55f1258397206eb31a137..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54708 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 diff --git a/tests/integration/__pycache__/test_semantic_validation.cpython-314-pytest-8.4.2.pyc b/tests/integration/__pycache__/test_semantic_validation.cpython-314-pytest-8.4.2.pyc deleted file mode 100644 index 73c6409d9ea0a4e827f5dc8b6b22c4632fed6ee1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24491 zcmeG^Yiu0HdAoPZd-Cr1kVs0T#G@&RI*H;#q(qUDNKv+^mrb3P$|*r;T~6eYJcztI z?H=_wCpGQ3HJuoZiUb7(w6*-Bsf7GtfC5!epmoy1iO~eO(=np7ap3?BQ1nMzMRFV1 zKZ<_e%=KE&1-{;{V{NI25DA7>MaU+<~fVg?O{*gSb}oLtG~YAl@RD zLA+Ju8@W(<_Rvs#DwfP7MuJyjlZnw-CXq@8GjTa12gg!UFg$U6axyg)51ttcUP_Ey zk~1+W6O`g3iF90U84U4?5RPRg6sJ5QCDIvL@r1v0?!=kFaR0dzBkH`8@#BoyIZk+T z1mYPk!i9~s>MM%8XcO(C&;@NUq7j|iV_1^|gEQ>fhc(MF^q{G%J&>GPpI)};kjQKE(!yFp8PPK@P7rvRI zC&Am8LjyOgLgzSb=$XeRn2 zu2#MXqI-Cw*1!O}N-NWU8@PyDgR1>b@M7Q~pDsDbOIO4|BYfTU@SnCPxKKs5`5f%g zplq>uuO>1RbTbD>Qprp_nQ8era3vvSrel+PM&t6OOe(F|Iy;n-@g(f*JG|o5N=uH3 z;u%q~r?0mu_Q`k>Q|*c)E=eg##!LrB`?J*yY0xS_71PPlp5Vu2p5B-&#{orb-LaR9Zn)n*|9snBqB-zK#ei8k3ar=tyjG5;~@(k`r(yt^yyKKSuK4>& z5|HLGoFt`EYZAYfo{S|4I=$mj-0C|(3#Ym$iX$P*({Wkh6B2G6#ft-@koOuh`;3`R znxW(9GG@AEL^L~sT2KaCCt!J7C#NsPD>fUu zSv50|^R>P2_0L}U=E0oMH`hR-ytj5y=%arNLf`B`mSc%GJ6Q6b&}Yc8Vt_Pzh2@}; zmbkt@)??S%H(&9qMxB6ce($|w&!MWvLDDy0Nu{aaB=Gfl9jlzu`f14WdwM0Bi+ z`h0$r5@@>UTGv?3v-0UtN~Gb8qJ>wZl&e$KWhtfT1zNb2+Ev1CC&4g^4O*H0y9~AS zF>2>4qIPAgQM>q5I&+;-JB5>Q4kW~fN(rfxko_d&LGob=S3nA2gmd(IMpcgQON(*m$2Q&)lDA(fG8FxrF>N(~Y)UYt~i5iB+*)ngRI2)9e}f1yY1z#2U;3)7@#PCTzI-z_fBc>HA9ww*>z}&wozLs&^96=J zYY}}yM9?Q-Q2bjEY7u>^IhH_#sg~UnY7IG743H3E>W#GAeH|hINAzh14kb`S5al2* zmisetGo91vNf%LgDrfhf2}bU6&jm4*mo;?j0t`=5;n2VMiV{|g$M3T*!Y z!l(*bk1*Rg_!_g?8lHV6pmA5rauY4FjD}wT@@CW zW&8F1mI!8Pe_*Wz5fSft#!8Wy{w&L}>a(lO=O|_S^?sIP)ce8MP5ZdbTH$ zBa_pk@nABQj9*L0L`oPL8~0GmX~LG<;DvQ;nXMfnta6Z!pm+dMIkqME69fys7kK{G zwekGDL=ZrhpJLm!pjlMA=(zTdOL_(ifQjKGGUgqa!Y@$TiBSlnT@cCm!E3BCMaRu6 zqhobGqja_*4_msFhyBpOl?EuI+C5jE6Cip6*u-x7w;*&Q zqE&M&fv8n2yC-xTa;z8tA!^kdX}SA4L;yZl&e{}&?p&SuL9`a0@dVz3v&OJr6;{Kr z+V`8beG2%sjNsSuBK!(UqIKb{&kw%>B@j#2HP+7#zar*`wWT3!jgNKwx;ifY?eVKi z`+`Jw5q|Z2;`r68{axK~Y z9z*G#J@I7h;$&Q&h>fPM2DR+e=swT(bZq2OY&XNXa}X2B7n}TO+sc++7A)v(`|`lh|fN!YQutwq^3%vIy2CzsX8+t zm9z*FYEfrMZXq&?=W9Dbj|R%K&C!vG_{gQGK2(q?$Q;S*C$LgG4zYBtRMx1sYBOd! zjF~Q~k)s-|_I4ThNsTn4E{l?9awM_zUGznko`ZfJ@Gl?Wmy+c6ysv$}so?9G8Tgf^ zH|j@n3=xv!e)_i{^dmV|b1Z=bSS`CJ^c!-l7yuyw)*ETL`#MAbj^tQvQxN)db>;`r zS^)OITb&b{Z#Dd7H~hTSce4+E=K2b?&G4J6ZO(g}7X|gNAT-Y&qPd^z$pvT+#2(vV z5?)bFLT{R08Ut(z(VI0J@GcRwKFM<%!x_v{VeEuS7&Gfon8*SHRs-ng{e)Qv6fp}= zHA`%EHL|4&V@#l3MpMN4fiSif&63V6tgcyFmRTU0rIo}gebj3gt5CB<#VXJ&h03zK zmKCeW>B&In-r$wEBm=E!k?^FDibYOL;fJ>}nULDBiAjfa$15RsK@>@A!MwT#sSCPU z2rQwM1(vbSy;1cQq~idgAEEpdqTfOfZ;)Yrx3onopeq41J-=ti%xgn&z;yvHSyrSx ze|pT!(8)Sc9P9U49y5!jqVE$|p8EmC(W7F2k@CDe+p;pUlVVpV5}*nyLU@W(EtYho zhk8si<||gDTVg(G0Q-RmZmkF3voao2hrw{!DS-1l!un5$Ot`Fj#WTfC1>du4JyZPM zLUTo@hsO@X=^;ecT-rAG>S#|a=@MY_AS`cRqX}i8(n0!1g07rpDswZJwl+(djf6|9 zD&o?fqApjJXXKV{WkCa--~Huo!b2EXF)(w_zVJrN|%rJ}Cbb&cWI2 zu5%x-ey|V9*I+UB+3bUgi05>vCtsQeUm0h`@* z?gG{ic0uLu%r4jvDgAtQfx&LlozN^OAr-35ZYON<*!1M2YR_!6fWDfNE{%aI)hzxi z4mmzDEyY7N2{8fx|w+jIA9GY6M_=)C037Aax)}n%Mz#wR-4=t1`Rn@44?oo%R(!by>9>t54Z)oU=>yYYC;Ed zhn~+Jd?DAQ7P4BJ0Ko93)xpK81No{0cdOsoR;W5YbLQcuodsX_&H5Ytw~xd{`Zn;HCcqrneE#NbCg5dPH9p&N?Mq3he`tL9y~E!M};Fgkd*irU5Uefjcz^W%l` z-kDPm8}}5dd*AMvi_KTx?f-t=Tl^gVb`PvwuDaK-d}nd_AR^0mc2U5;1>r1NJ~c}V zA;tw$%kCBBSTTSi>!r71+4}~d@BmyswN(LXLcO`ZGr8VyuF3pR+6F4 ze2slFT9duI(Ji`!cN-lL|Fp&}`h=hEa6ml5?0%pTo{oTKOL($C1U=%&!lkME3oyVs zld3c58o{@6Td*n9Uy3L+qy`j|q5K}!1~K45+Q1_96y8acm70Q4IKz(CqR zjAol8L;~9Q(`6U9ba|vKQoh7#=;Ru|T-4@nK?p_Pu76$MF025!{phQ0`Rxv)6@XZ_uCcCdpRpNcW2E+jtBg@!85mocSZ%b~ ztlG9*Yim-57<*dpvr714o3+{3e@i)WLnHvZjj370jmBnTRiwhS+bY+w+bXs3YQO4k zD}x>9gs+whx9VfjQs@6A+@_`VU*>GLA+kYRk#SHW)^W%9(?0{J0WOSZ@1_tbjci~& zH%2xt*>lw^?zyU>Jy)f@#nU|pd#>hF*mG=#wH00?ZDajl&(-`M?72;ms?TfB9kZVv zrLHyTeyck4`I%q}snAx{*+F-{3WCK`3`EJ;WKeU38`WKKC1elJg=~s{B$g)fW@5FM8H4>L)#g>vK9;eC`jgG-IN27`Zy%CccrDS9R9>7?S(L9XIpf?ONu zA~K^eN4f>HBB1A@;+EpE(I{E|Ftj5pr3l2EF@WC$d`#MTnj(Ph_Y@KAL)Ap4SG?L> z!LXz#_Wue#%&U5MN3r-kDbXDk+o^$dKP#r@T>Fgt#!0jl~6KGD4s={EG<(VS!P}DvE^+S;*8Gt1bstELKhI``R zN~(S#_`v3&vidvMzTL7|(Uh-fTC8ZvSG3G;`gujq%;^V$c`+c|%}P{11BH z>YwX}EL7!cPrVQHiKj;_p{o;pqY)9&8 zC3t~C!3WQa?+yHh)cr3l=n?Zh;v-V>rc9gC_=A(;dz*?YK3p9JjB*(utVSJ)4jx8H z`}~^1*K2O`Mqu=v>HE=vJ@9Y5acQw?N4{!DZevrfsV{dVoa;NAD;4QG8hfkn+b8Dx zifSp;M=q|iZn0u_zGC<7`F*Q~i^s!d7wi z%)?#Xg{`OVwB9;<_dG1t@LQMXF5hXLJ(Jsd>ix>98!s0sn*grw9Dlo={^ly1Znx(v zn_)yy3M&Qi2S9lq&csmbvx(+2rT}UZ)=yOyt=66?rPkmC#}rE@ zA=ctkoiI3rZcTQATFj+!!o6P)4Ji$FF+&TKLhvCL9V zG6?*X>XQ~9ZOIOMwqKHC=`@)2>)d85xBy7;(bkca6mPv4ljALy!190jb_VyjR*hxF zF4C9bCCo=YPL;VeaKBrN9R|$Yukq9e)mOv^04zlr*R}>OQ0M+a9>bx`HUvjFt7%Lv zcRXY1n!Ll3eNqP>)#gE#t^(vghkyB35P=t*%TB!DJj4rbN8Y#N*42WqmDpU>HWd6F zH+S4Pd+X$U`P+lvx;%UN=8l=;Ie!P9OI-ctp`36S&m|xt=Msk(1^inO4x@3qnqvvn z+^c2xgu{j$D+WljS6L1kX}SA4L;#MC$SROWNjm@(_fBi&Hy?M%b?!iXzPC?D9=*rpCXAECAT7+C<;F zJQ=B0TK``0?8+3ttDTVrZLHdJRjst%-;!7^?GG#E6a9ucvh1h7sTf$bEhBxV6Bf_# z+SkPD>;u+BdPDSpOF~7qk&w0`A2%sJmAV2BZrZ7SOSabFQO5k(s9W1AzH0{4+#pP-fQGh98Ou5;V~NZ4s!>2)?DLeO6s}On^cvSt&!Vj zPw*i-HDLf_P;T%JcgLpKTG|LLl2KQ+Llx59hfryAEiLsb2MEDg;;E*-zvi*la)@5m z)Z4;(ejnh;+aUT67{p7Z5i?eX|4Bz2L>JNF0n$r)Le&c1B~NMm8nH8O zcoH=14%qprPdt|fBaf#vp5xZ|6)oWreotw9$5I-vo4_$LA0$4AS7TBVj#*l=KF_82 z^^2*PG#Z=+$#ccKSw2%LuQ<=sF)A)?go9ERcDwWvL`GUKeGLkhqw?yDu0ZAg5y3S= zWTf)f=lb9HBbCbUn&;ncr9@tO8QMuR7$KRpqS?}`Sn+j;)v)wk+?$G*b+AjM zTe5#euc}JprFyBcF^_&L6&%DeEz>G0JFBMJogPHZw`W{RO{Y<5XSnR+2r2;Sl^;-= zk~5z8$V4jm%!xSMcKytn?gFV-ReQ0Kk$5_zUbxHN&UmbCxJgjD0$Ww;f@sYi-Q?7g zOl_1wm;MwW{0O1^1R}hD%1`+Bpjq?AjDC-!at$J)Tsyuf;NOC99NBj@#}ddet7Z3u zy5PBeH|hIN9CH@rXU>8)%V`Lau+U1H9wCwf=3Y?8md>E(dcMu1dhmE z+BLo8jzwitlwR!HLM1oioFBg`B{FbHFDnAaRa!<=r*O(n?g9o&0l1}nGI5cf!rSHR zvh)?0Iw^+HMTivd(6i#n@VTMrb0#kQ^uLoWU+~EJLh-G*LnFpkLyU*4P`ZzV3hf|c{_iOe;nq0eDC9+mw%SWX3z2;)>ZN+c(PLe E54M7j0ssI2 diff --git a/tests/integration/test_integration.py b/tests/integration/test_integration.py index 2624753..baf4708 100644 --- a/tests/integration/test_integration.py +++ b/tests/integration/test_integration.py @@ -11,7 +11,7 @@ import os # Use actual project root PROJECT_ROOT = Path('/home/lukas/Code/virt/phyllomeos') -SCRIPTS_DIR = PROJECT_ROOT / 'scripts' +RECIPE_GENERATOR_DIR = PROJECT_ROOT / 'recipe-generator' RECIPE_DIR = PROJECT_ROOT / 'recipes' FRAGMENTS_DIR = PROJECT_ROOT / 'fragments' CONTAINER_DIR = PROJECT_ROOT / 'tests' / 'container' @@ -19,8 +19,8 @@ CONTAINER_DIR = PROJECT_ROOT / 'tests' / 'container' def test_generate_recipes_from_manifest(): """Test generating all recipes from manifest.""" - os.chdir(SCRIPTS_DIR) - + os.chdir(RECIPE_GENERATOR_DIR) + result = subprocess.run( ['python3', 'generate_recipe.py', '--manifest', 'recipes_manifest.yaml', @@ -28,7 +28,7 @@ def test_generate_recipes_from_manifest(): capture_output=True, text=True ) - + assert result.returncode == 0, f"Recipe generation failed: {result.stderr}" assert 'Generating:' in result.stdout @@ -51,7 +51,7 @@ def test_make_targets(): # Test generate-recipes result = subprocess.run( ['make', 'generate-recipes'], - cwd=SCRIPTS_DIR, + cwd=RECIPE_GENERATOR_DIR, capture_output=True, text=True ) diff --git a/tests/test_recipe_generator.py b/tests/test_recipe_generator.py index 585f26c..5e1f548 100644 --- a/tests/test_recipe_generator.py +++ b/tests/test_recipe_generator.py @@ -3,11 +3,9 @@ import pytest from pathlib import Path import sys -import os -# Add scripts directory to path -SCRIPTS_DIR = Path(__file__).parent.parent / 'scripts' -sys.path.insert(0, str(SCRIPTS_DIR)) +RECIPE_GENERATOR_DIR = Path(__file__).parent.parent / 'recipe-generator' +sys.path.insert(0, str(RECIPE_GENERATOR_DIR)) from generate_recipe import RecipeGenerator @@ -19,7 +17,11 @@ class TestRecipeGenerator: def setup_method(self): """Set up test fixtures.""" - self.generator = RecipeGenerator(Path('ingredients'), Path('recipe_templates.yaml')) + project_root = Path(__file__).parent.parent + self.generator = RecipeGenerator( + project_root / 'ingredients', + project_root / 'recipe-generator' / 'recipe_templates.yaml' + ) def test_template_loading(self): """Test that templates are loaded correctly."""