refactor: Simplify template logic - reduce from 6 to 3 categories, remove variant_type, keep validation, remove tests
Simplified template logic: reduced from 6 categories (required, modifiers, optional, versioned, conditional, flags) to 3 categories (required, modifiers, optional). Removed variant_type and replaced with modifier-based approach (version, bootloader replaced, hardware_support). All validation methods kept for recipe generation and validation. Removed tests directory (tests/test_recipe_generator.py, tests/integration/, tests/container/). Removed non-ISO workflows (validate-recipes, test-generation, container-tests, validate-ingredients). Updated Makefile, requirements.txt, and documentation. All 20 recipes successfully generated, validated, and flattened.
This commit is contained in:
@@ -1,38 +0,0 @@
|
|||||||
name: container-tests
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
paths:
|
|
||||||
- 'tests/**/*.py'
|
|
||||||
- 'tests/container/**'
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- 'tests/**/*.py'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test:
|
|
||||||
runs-on: fedora
|
|
||||||
container:
|
|
||||||
image: git.phyllo.me/devops/fedora-runner-image:latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: https://git.phyllo.me/devops/checkout@v5
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Build test container
|
|
||||||
run: |
|
|
||||||
cd recipe-generator
|
|
||||||
podman build -t phyllo/test-runner ../tests/container/
|
|
||||||
|
|
||||||
- name: Run tests in container
|
|
||||||
run: |
|
|
||||||
podman run --rm -v $(pwd):/phyllomeos:ro phyllo/test-runner
|
|
||||||
|
|
||||||
- name: Upload test results
|
|
||||||
if: always()
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: container-test-results
|
|
||||||
path: _pytest_cache/
|
|
||||||
if-no-files-found: ignore
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
name: test-generation
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
paths:
|
|
||||||
- 'recipe-generator/**/*.py'
|
|
||||||
- 'recipe-generator/**/*.yaml'
|
|
||||||
- 'ingredients/**/*.ks'
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- 'recipe-generator/**/*.py'
|
|
||||||
- 'recipe-generator/**/*.yaml'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
generate:
|
|
||||||
runs-on: fedora
|
|
||||||
container:
|
|
||||||
image: git.phyllo.me/devops/fedora-runner-image:latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: https://git.phyllo.me/devops/checkout@v5
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
pip install PyYAML pykickstart
|
|
||||||
|
|
||||||
- name: Generate all variants
|
|
||||||
run: |
|
|
||||||
cd recipe-generator
|
|
||||||
python3 generate_recipe.py \
|
|
||||||
--manifest recipes_manifest.yaml \
|
|
||||||
--output-dir ../recipes/
|
|
||||||
|
|
||||||
- name: Verify 16 recipes created
|
|
||||||
run: |
|
|
||||||
count=$(ls recipes/*.cfg | wc -l)
|
|
||||||
if [ $count -ne 16 ]; then
|
|
||||||
echo "Expected 16 recipes, got $count"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "✓ Generated $count recipes"
|
|
||||||
|
|
||||||
- name: Upload generated recipes
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: generated-recipes
|
|
||||||
path: recipes/
|
|
||||||
if-no-files-found: error
|
|
||||||
retention-days: 7
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
name: validate-ingredients
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
paths:
|
|
||||||
- 'ingredients/**/*.ks'
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- 'ingredients/**/*.ks'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
validate:
|
|
||||||
runs-on: fedora
|
|
||||||
container:
|
|
||||||
image: git.phyllo.me/devops/fedora-runner-image:latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: https://git.phyllo.me/devops/checkout@v5
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Install pykickstart
|
|
||||||
run: pip install pykickstart
|
|
||||||
|
|
||||||
- name: Validate all ingredients
|
|
||||||
run: |
|
|
||||||
errors=0
|
|
||||||
for ingredient in $(find ingredients -name "*.ks"); do
|
|
||||||
if python3 -c "
|
|
||||||
from pykickstart.parser import KickstartParser
|
|
||||||
from pykickstart.version import makeVersion, DEVEL
|
|
||||||
parser = KickstartParser(makeVersion(DEVEL))
|
|
||||||
parser.readKickstart(open('$ingredient').read())
|
|
||||||
" 2>/dev/null; then
|
|
||||||
echo "✓ $ingredient"
|
|
||||||
else
|
|
||||||
echo "✗ $ingredient"
|
|
||||||
errors=$((errors + 1))
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
echo "Ingredient validation complete: $errors errors"
|
|
||||||
exit $errors
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
name: validate-recipes
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [main, develop]
|
|
||||||
pull_request:
|
|
||||||
branches: [main]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
validate:
|
|
||||||
runs-on: fedora
|
|
||||||
container:
|
|
||||||
image: git.phyllo.me/devops/fedora-runner-image:latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: https://git.phyllo.me/devops/checkout@v5
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
pip install PyYAML pytest pykickstart
|
|
||||||
|
|
||||||
- name: Generate all recipes
|
|
||||||
run: |
|
|
||||||
cd recipe-generator
|
|
||||||
make generate-recipes
|
|
||||||
|
|
||||||
- name: Validate recipes (strict mode)
|
|
||||||
run: |
|
|
||||||
cd recipe-generator
|
|
||||||
python3 generate_recipe.py --validate ../recipes/*.cfg --strict
|
|
||||||
|
|
||||||
- name: Run unit tests
|
|
||||||
run: |
|
|
||||||
cd recipe-generator
|
|
||||||
make test
|
|
||||||
|
|
||||||
- name: Run integration tests
|
|
||||||
run: |
|
|
||||||
cd recipe-generator
|
|
||||||
make test-integration
|
|
||||||
|
|
||||||
- name: Upload test results
|
|
||||||
if: always()
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: test-results
|
|
||||||
path: _pytest_cache/
|
|
||||||
if-no-files-found: ignore
|
|
||||||
-116
@@ -392,122 +392,6 @@ done
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Testing
|
|
||||||
|
|
||||||
Phyllome OS uses a comprehensive test suite with 36+ tests covering unit, integration, and regression scenarios.
|
|
||||||
|
|
||||||
### Test Suite Structure
|
|
||||||
|
|
||||||
| Test File | Tests | Coverage |
|
|
||||||
|-----------|-------|----------|
|
|
||||||
| `tests/test_recipe_generator.py` | 36 | Unit tests for RecipeGenerator |
|
|
||||||
| `tests/integration/test_integration.py` | 5+ | End-to-end workflow tests |
|
|
||||||
| `tests/integration/test_ingredients.py` | ~15 | Fragment validation |
|
|
||||||
| `tests/integration/test_recipe_composition.py` | ~10 | Recipe generation |
|
|
||||||
| `tests/integration/test_semantic_validation.py` | ~10 | pykickstart validation |
|
|
||||||
| `tests/integration/test_golden_masters.py` | ~5 | Regression tests |
|
|
||||||
|
|
||||||
### Running Tests
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd scripts
|
|
||||||
|
|
||||||
# All tests (unit + integration)
|
|
||||||
make test
|
|
||||||
|
|
||||||
# Unit tests only
|
|
||||||
python3 -m pytest tests/test_recipe_generator.py -v
|
|
||||||
|
|
||||||
# Integration tests only
|
|
||||||
make test-integration
|
|
||||||
|
|
||||||
# Containerized tests
|
|
||||||
make test-container
|
|
||||||
# or: podman run --rm -v .:/phyllomeos:ro phyllo/test-runner
|
|
||||||
```
|
|
||||||
|
|
||||||
**Expected output:**
|
|
||||||
```
|
|
||||||
============================= test session starts =============================
|
|
||||||
collected 41 items
|
|
||||||
|
|
||||||
tests/test_recipe_generator.py ............. [ 29%]
|
|
||||||
tests/integration/test_integration.py ..... [ 43%]
|
|
||||||
...
|
|
||||||
|
|
||||||
============================== 41 passed in 2.34s ==============================
|
|
||||||
```
|
|
||||||
|
|
||||||
### Fragment Validation Test
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Test all ingredients with pykickstart
|
|
||||||
for fragment in $(find ingredients -name "*.ks"); do
|
|
||||||
python3 -c "
|
|
||||||
from pykickstart.parser import KickstartParser
|
|
||||||
from pykickstart.version import makeVersion, DEVEL
|
|
||||||
parser = KickstartParser(makeVersion(DEVEL))
|
|
||||||
parser.readKickstart(open('$fragment').read())
|
|
||||||
" && echo "✓ $fragment" || echo "✗ $fragment"
|
|
||||||
done
|
|
||||||
```
|
|
||||||
|
|
||||||
### Adding New Tests
|
|
||||||
|
|
||||||
**Unit test example:**
|
|
||||||
|
|
||||||
```python
|
|
||||||
# tests/test_recipe_generator.py
|
|
||||||
|
|
||||||
def test_generate_recipe_with_new_modifier():
|
|
||||||
"""Test recipe generation with custom modifier."""
|
|
||||||
content = self.generator.generate_recipe(
|
|
||||||
'virtual-desktop', '43',
|
|
||||||
desktop='gnome',
|
|
||||||
storage='standard',
|
|
||||||
security='secure'
|
|
||||||
)
|
|
||||||
assert '# A recipe for a virtual desktop' in content
|
|
||||||
assert '%ksappend ingredients/shared/desktop/gnome/packages.ks' in content
|
|
||||||
```
|
|
||||||
|
|
||||||
**Integration test example:**
|
|
||||||
|
|
||||||
```python
|
|
||||||
# tests/integration/test_recipe_composition.py
|
|
||||||
|
|
||||||
def test_manifest_generates_correct_count():
|
|
||||||
"""Test manifest generates expected number of recipes."""
|
|
||||||
result = subprocess.run(
|
|
||||||
['python3', 'generate_recipe.py',
|
|
||||||
'--manifest', 'recipes_manifest.yaml',
|
|
||||||
'--output-dir', '../recipes/'],
|
|
||||||
capture_output=True, text=True
|
|
||||||
)
|
|
||||||
assert result.returncode == 0
|
|
||||||
recipe_count = len(list(Path('../recipes').glob('*.cfg')))
|
|
||||||
assert recipe_count == 16
|
|
||||||
```
|
|
||||||
|
|
||||||
### Golden Master Tests
|
|
||||||
|
|
||||||
Golden masters (expected outputs) are stored in `tests/fixtures/expected_recipes/`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# View expected output for virtual-desktop
|
|
||||||
cat tests/fixtures/expected_recipes/virtual-desktop_43.cfg
|
|
||||||
```
|
|
||||||
|
|
||||||
**To update golden masters** (after intentional changes):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Generate and compare
|
|
||||||
python3 -m pytest tests/integration/test_golden_masters.py -v
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## CI/CD
|
|
||||||
|
|
||||||
The project uses Gitea Actions for automated testing and building.
|
The project uses Gitea Actions for automated testing and building.
|
||||||
|
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ This is a quick-reference guide for developers. For comprehensive coverage, see
|
|||||||
```bash
|
```bash
|
||||||
# Prerequisites
|
# Prerequisites
|
||||||
sudo dnf install qemu libvirt virt-install pykickstart
|
sudo dnf install qemu libvirt virt-install pykickstart
|
||||||
pip install PyYAML pytest
|
pip install PyYAML
|
||||||
|
|
||||||
# Verify setup
|
# Verify setup
|
||||||
cd recipe-generator && make generate-recipes && make test
|
cd recipe-generator && make generate-recipes
|
||||||
```
|
```
|
||||||
|
|
||||||
## Core Workflows
|
## Core Workflows
|
||||||
@@ -35,13 +35,6 @@ new-package
|
|||||||
cd recipe-generator && make generate-recipes && make validate-recipes
|
cd recipe-generator && make generate-recipes && make validate-recipes
|
||||||
```
|
```
|
||||||
|
|
||||||
### Run Tests
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd recipe-generator
|
|
||||||
make test # All tests
|
|
||||||
make test-integration # Integration only
|
|
||||||
make test-container # Containerized
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Validate Fragments
|
### Validate Fragments
|
||||||
|
|||||||
@@ -4,10 +4,9 @@
|
|||||||
|
|
||||||
Provided that some dependencies are met (`libvirt` is running on your computer, QEMU is installed, etc), one could run the following script to deploy virtual machines, including Phyllome OS itself.
|
Provided that some dependencies are met (`libvirt` is running on your computer, QEMU is installed, etc), one could run the following script to deploy virtual machines, including Phyllome OS itself.
|
||||||
|
|
||||||
- Make the script executable:
|
- :
|
||||||
|
|
||||||
```
|
```
|
||||||
chmod +x deploy-vm.sh
|
|
||||||
```
|
```
|
||||||
|
|
||||||
- Execute it and pick `virtual-desktop-hypervisor` when prompted:
|
- Execute it and pick `virtual-desktop-hypervisor` when prompted:
|
||||||
@@ -49,149 +48,3 @@ Each ingredient represents a feature or a set of integrated features, such as a
|
|||||||
- Ingredients prefixed with *live* such as `live-core.cfg` are to be used with live editions only
|
- Ingredients prefixed with *live* such as `live-core.cfg` are to be used with live editions only
|
||||||
- *core* ingredients are meant be used in all their respective recipes, *base* ingredients, recommended but optional, and extra provides more stuff (sic)
|
- *core* ingredients are meant be used in all their respective recipes, *base* ingredients, recommended but optional, and extra provides more stuff (sic)
|
||||||
|
|
||||||
## Development
|
|
||||||
|
|
||||||
Using a pull request, you can suggest a modification to an existing ingredient or create a new ingredient from scratch.
|
|
||||||
|
|
||||||
### Requirements
|
|
||||||
|
|
||||||
- `qemu`
|
|
||||||
- `libvirt`
|
|
||||||
- `virt-install`
|
|
||||||
- `pykickstart`
|
|
||||||
|
|
||||||
### Example 1: add a new package and include it into a recipe
|
|
||||||
|
|
||||||
- Add [Luanti](https://www.luanti.org/), a free and open-source sandbox video game engine formerly known as Minetest, as a standalone ingredient, using the `echo` command
|
|
||||||
|
|
||||||
```
|
|
||||||
echo "%packages --exclude-weakdeps # Beginning of the package section. Does not include weak dependencies
|
|
||||||
|
|
||||||
luanti # Multiplayer infinite-world block sandbox with survival mode
|
|
||||||
|
|
||||||
%end # End of the packages section" > ingredients/extra-luanti.cfg
|
|
||||||
```
|
|
||||||
|
|
||||||
Instead of creating a recipe from scratch, let's make a copy of the `virtual-desktop.cfg` recipe, which provide a Desktop environment necessary for *luanti* to function
|
|
||||||
|
|
||||||
```
|
|
||||||
cp recipes/virtual-desktop.cfg recipes/virtual-desktop-luanti.cfg
|
|
||||||
```
|
|
||||||
|
|
||||||
- Add the extra ingredient to the new recipe:
|
|
||||||
|
|
||||||
```
|
|
||||||
echo "%include ../ingredients/extra-luanti.cfg # Sandbox video game engine" >> recipes/virtual-desktop-luanti.cfg
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Flatten
|
|
||||||
|
|
||||||
- Prepare the dish by following the recipe, a process called 'flattening'
|
|
||||||
|
|
||||||
```
|
|
||||||
ksflatten -c recipes/virtual-desktop-luanti.cfg -o dishes/virtual-desktop-luanti.cfg
|
|
||||||
```
|
|
||||||
|
|
||||||
> If any errors are detected, go back and fix them.
|
|
||||||
|
|
||||||
It is time to test the new dish!
|
|
||||||
|
|
||||||
#### Kickstart
|
|
||||||
|
|
||||||
- Make the `deploy-vm.sh` script executable
|
|
||||||
|
|
||||||
```
|
|
||||||
chmod +x deploy-vm.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
- Execute the script
|
|
||||||
|
|
||||||
```
|
|
||||||
./deploy-vm.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
- Select the new dish, *virtual-desktop-luanti*
|
|
||||||
|
|
||||||
```
|
|
||||||
[...]
|
|
||||||
Available files:
|
|
||||||
1. desktop-hypervisor-amdcpu
|
|
||||||
[...]
|
|
||||||
14. virtual-desktop-luanti
|
|
||||||
```
|
|
||||||
|
|
||||||
- When the installation is done, the machine will shut down
|
|
||||||
|
|
||||||
- Start it again, and ensure that Luanti has correctly been installed
|
|
||||||
|
|
||||||
That's it !
|
|
||||||
|
|
||||||
### Example 2: Create a new recipe from the existing list of ingredients
|
|
||||||
|
|
||||||
The file `recipes/_list-of-ingredients.cfg` can be copied and edited to create your own remix of Phyllome OS, which itself is a remix of Fedora.
|
|
||||||
|
|
||||||
```
|
|
||||||
cp recipes/_list-of-ingredients.cfg recipes/my-new-distro.cfg
|
|
||||||
```
|
|
||||||
|
|
||||||
Then edit the said file to include your favorite ingredient
|
|
||||||
|
|
||||||
```
|
|
||||||
nano recipes/my-new-distro.cfg
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
# __ ____ ____ _____
|
|
||||||
# ____ / /_ __ __/ / /___ ____ ___ ___ / __ \/ ___/
|
|
||||||
# / __ \/ __ \/ / / / / / __ \/ __ `__ \/ _ \ / / / /\__ \
|
|
||||||
# / /_/ / / / / /_/ / / / /_/ / / / / / / __/ / /_/ /___/ /
|
|
||||||
# / .___/_/ /_/\__, /_/_/\____/_/ /_/ /_/\___/ \____//____/
|
|
||||||
# /_/ /____/
|
|
||||||
|
|
||||||
# The list of ingredients for composing Phyllome OS
|
|
||||||
# Uncomment lines with "%include" to enable ingredient
|
|
||||||
|
|
||||||
# Installation method
|
|
||||||
# Exactly one option has to be picked
|
|
||||||
# %include ../ingredients/core.cfg # Text mode
|
|
||||||
# %include ../ingredients/live-core.cfg # For live systems only
|
|
||||||
# Documentation: https://pykickstart.readthedocs.io/en/latest/kickstart-docs.html#graphical-or-text-or-cmdline
|
|
||||||
|
|
||||||
# Storage configuration
|
|
||||||
# Exactly one option has to be picked
|
|
||||||
# WARNING !!! Will erase local disks!
|
|
||||||
# %include ../ingredients/core-storage.cfg # Basic ext4 partition layout for UEFI-based systems
|
|
||||||
# %include ../ingredients/live-core-storage.cfg # For live systems only
|
|
||||||
# Documentation: https://pykickstart.readthedocs.io/en/latest/kickstart-docs.html#part-or-partition
|
|
||||||
[...]
|
|
||||||
```
|
|
||||||
|
|
||||||
- Once you are done, you can [flatten](#flatten) the file and [kickstart](#kickstart) it as explained in the previous section.
|
|
||||||
|
|
||||||
## FAQ
|
|
||||||
|
|
||||||
If multiple dishes are affected by your ingredient, you can flatten them all
|
|
||||||
|
|
||||||
- Navigate to the recipes' directory
|
|
||||||
|
|
||||||
```
|
|
||||||
cd recipes
|
|
||||||
```
|
|
||||||
|
|
||||||
- Then use the following
|
|
||||||
|
|
||||||
```
|
|
||||||
for filename in *.cfg; do ksflatten -c "$filename" -o "../dishes/$filename"; done
|
|
||||||
```
|
|
||||||
|
|
||||||
The following message can safetly be ignored:
|
|
||||||
|
|
||||||
```
|
|
||||||
/usr/lib/python3.13/site-packages/pykickstart/commands/partition.py:461: KickstartParseWarning: A partition with the mountpoint / has already been defined.
|
|
||||||
```
|
|
||||||
|
|
||||||
## Acknowledgement
|
|
||||||
|
|
||||||
Thanks to the main contributors of the official Fedora kickstart files repository, and related tools:
|
|
||||||
|
|
||||||
> Adam Miller, Bastien Nocera, Bruno Wolff III, Bryan Kearney, Chitlesh Goorah, Christoph Wickert, Colin Walters, Fabian Affolter, Igor Pires Soares, Jens Petersen, Jeremy Katz, Jeroen van Meeuwen Jesse Keating, Luya Tshimbalanga, Matthias Clasen, Pedro Silva, Rahul Sundaram, Sebastian Dziallas Sebastian Vahl, wart. More information here : https://pagure.io/fedora-kickstarts
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
# Generated by pykickstart v3.69
|
|
||||||
#version=DEVEL
|
|
||||||
# Keyboard layouts
|
|
||||||
keyboard --xlayouts='ch (fr)'
|
|
||||||
# System language
|
|
||||||
lang en_US.UTF-8
|
|
||||||
# Network information
|
|
||||||
network --bootproto=dhcp --device=link --hostname=phyllome-alpha --activate
|
|
||||||
# Shutdown after installation
|
|
||||||
shutdown
|
|
||||||
repo --name="fedora" --mirrorlist=https://mirrors.fedoraproject.org/mirrorlist?repo=fedora-43&arch=x86_64
|
|
||||||
repo --name="updates" --mirrorlist=https://mirrors.fedoraproject.org/mirrorlist?repo=updates-released-f43&arch=x86_64
|
|
||||||
repo --name="rpmfusion-nonfree" --mirrorlist=https://mirrors.rpmfusion.org/mirrorlist?repo=nonfree-fedora-$releasever&arch=$basearch --includepkgs="rpmfusion-nonfree-release"
|
|
||||||
repo --name="rpmfusion-nonfree-updates" --mirrorlist=https://mirrors.rpmfusion.org/mirrorlist?repo=nonfree-fedora-updates-released-$releasever&arch=$basearch --includepkgs="rpmfusion-nonfree-release"
|
|
||||||
# System services
|
|
||||||
services --enabled="NetworkManager,systemd-resolved"
|
|
||||||
# System timezone
|
|
||||||
timezone Europe/Zurich --utc
|
|
||||||
# Use network installation
|
|
||||||
url --mirrorlist="https://mirrors.fedoraproject.org/mirrorlist?repo=fedora-43&arch=x86_64"
|
|
||||||
# System bootloader configuration
|
|
||||||
bootloader --location=mbr --timeout=1
|
|
||||||
# Clear the Master Boot Record
|
|
||||||
zerombr
|
|
||||||
# Partition clearing information
|
|
||||||
clearpart --all --initlabel
|
|
||||||
# Disk partitioning information
|
|
||||||
part / --fstype="ext4" --size=5120
|
|
||||||
part / --size=8576
|
|
||||||
|
|
||||||
%post --logfile=/mnt/sysimage/root/live-core-post.log
|
|
||||||
|
|
||||||
# Enable livesys services
|
|
||||||
systemctl enable livesys.service
|
|
||||||
systemctl enable livesys-late.service
|
|
||||||
|
|
||||||
# enable tmpfs for /tmp
|
|
||||||
systemctl enable tmp.mount
|
|
||||||
|
|
||||||
# make it so that we don't do writing to the overlay for things which
|
|
||||||
# are just tmpdirs/caches
|
|
||||||
# note https://bugzilla.redhat.com/show_bug.cgi?id=1135475
|
|
||||||
cat >> /etc/fstab << EOF
|
|
||||||
vartmp /var/tmp tmpfs defaults 0 0
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# work around for poor key import UI in PackageKit
|
|
||||||
rm -f /var/lib/rpm/__db*
|
|
||||||
echo "Packages within this LiveCD"
|
|
||||||
rpm -qa --qf '%{size}\t%{name}-%{version}-%{release}.%{arch}\n' |sort -rn
|
|
||||||
# Note that running rpm recreates the rpm db files which aren't needed or wanted
|
|
||||||
rm -f /var/lib/rpm/__db*
|
|
||||||
|
|
||||||
# go ahead and pre-make the man -k cache (#455968)
|
|
||||||
/usr/bin/mandb
|
|
||||||
|
|
||||||
# make sure there aren't core files lying around
|
|
||||||
rm -f /core*
|
|
||||||
|
|
||||||
# remove random seed, the newly installed instance should make it's own
|
|
||||||
rm -f /var/lib/systemd/random-seed
|
|
||||||
|
|
||||||
# convince readahead not to collect
|
|
||||||
# FIXME: for systemd
|
|
||||||
|
|
||||||
echo 'File created by kickstart. See systemd-update-done.service(8).' \
|
|
||||||
| tee /etc/.updated >/var/.updated
|
|
||||||
|
|
||||||
# Drop the rescue kernel and initramfs, we don't need them on the live media itself.
|
|
||||||
# See bug 1317709
|
|
||||||
rm -f /boot/*-rescue*
|
|
||||||
|
|
||||||
# Disable network service here, as doing it in the services line
|
|
||||||
# fails due to RHBZ #1369794
|
|
||||||
systemctl disable network
|
|
||||||
|
|
||||||
# Remove machine-id on pre generated images
|
|
||||||
rm -f /etc/machine-id
|
|
||||||
touch /etc/machine-id
|
|
||||||
|
|
||||||
%end
|
|
||||||
|
|
||||||
%post --logfile=/mnt/sysimage/root/post-live-session.log
|
|
||||||
|
|
||||||
# set livesys session type
|
|
||||||
sed -i 's/^livesys_session=.*/livesys_session="gnome"/' /etc/sysconfig/livesys
|
|
||||||
|
|
||||||
%end
|
|
||||||
|
|
||||||
%post
|
|
||||||
|
|
||||||
# Import RPM Fusion PGP Key. Courtesy of https://github.com/rpmfusion/rpmfusion-nonfree-remix-kickstarts/blob/master/rpmfusion-nonfree-live-base.ks
|
|
||||||
echo "== RPM Fusion Nonfree: Base section =="
|
|
||||||
echo "Importing RPM Fusion keys"
|
|
||||||
rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-rpmfusion-nonfree-fedora-*-primary
|
|
||||||
echo "List of packages from RPM Fusion Nonfree:"
|
|
||||||
rpm -qa --qf '%{NAME} %{SIGGPG:pgpsig} %{SIGPGP:pgpsig} \n' | grep -e 3DE8C682E38EE9BC0FDFEA47FCAE2EA87F858107 | awk ' { print $1 } ' | sort
|
|
||||||
echo "List of incuded RPM Fusion packages with their size:"
|
|
||||||
rpm -q --qf '%{SIZE} %{NAME}\n' $(rpm -qa --qf '%{NAME} %{SIGGPG:pgpsig} %{SIGPGP:pgpsig} \n' | grep -e 3DE8C682E38EE9BC0FDFEA47FCAE2EA87F858107 | awk ' { print $1 } ') | sort -n
|
|
||||||
echo
|
|
||||||
|
|
||||||
%end
|
|
||||||
|
|
||||||
%packages
|
|
||||||
@anaconda-tools
|
|
||||||
aajohan-comfortaa-fonts
|
|
||||||
dracut-live
|
|
||||||
glibc-all-langpacks
|
|
||||||
kernel
|
|
||||||
kernel-modules
|
|
||||||
kernel-modules-extra
|
|
||||||
livesys-scripts
|
|
||||||
|
|
||||||
%end
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
.PHONY: help generate-recipes validate-recipes test test-integration test-container clean clean-dishes install-deps flatten-dishes all
|
.PHONY: help generate-recipes validate-recipes clean clean-dishes install-deps flatten-dishes all
|
||||||
|
|
||||||
help:
|
help:
|
||||||
@echo "Phyllome OS Recipe Generator"
|
@echo "Phyllome OS Recipe Generator"
|
||||||
@@ -6,9 +6,6 @@ help:
|
|||||||
@echo "Available targets:"
|
@echo "Available targets:"
|
||||||
@echo " generate-recipes - Generate all recipes from manifest"
|
@echo " generate-recipes - Generate all recipes from manifest"
|
||||||
@echo " validate-recipes - Validate existing recipes"
|
@echo " validate-recipes - Validate existing recipes"
|
||||||
@echo " test - Run pytest test suite (unit + integration)"
|
|
||||||
@echo " test-integration - Run integration tests only"
|
|
||||||
@echo " test-container - Run all tests in container"
|
|
||||||
@echo " all - Generate, validate, and flatten all recipes (default)"
|
@echo " all - Generate, validate, and flatten all recipes (default)"
|
||||||
@echo " flatten-dishes - Flatten all recipes to dishes"
|
@echo " flatten-dishes - Flatten all recipes to dishes"
|
||||||
@echo " clean-dishes - Remove flattened dishes"
|
@echo " clean-dishes - Remove flattened dishes"
|
||||||
@@ -31,16 +28,6 @@ validate-recipes:
|
|||||||
python3 generate_recipe.py \
|
python3 generate_recipe.py \
|
||||||
--validate ../recipes/*.cfg
|
--validate ../recipes/*.cfg
|
||||||
|
|
||||||
test:
|
|
||||||
python3 -m pytest ../tests/ -v --tb=short
|
|
||||||
|
|
||||||
test-integration:
|
|
||||||
python3 -m pytest ../tests/integration/ -v --tb=short
|
|
||||||
|
|
||||||
test-container:
|
|
||||||
podman build -t phyllo/test-runner ../tests/container/
|
|
||||||
podman run --rm -v .:/phyllomeos:ro phyllo/test-runner
|
|
||||||
|
|
||||||
flatten-dishes:
|
flatten-dishes:
|
||||||
@echo "Flattening recipes to dishes..."
|
@echo "Flattening recipes to dishes..."
|
||||||
@python ../bin/ksflatten-relative ../recipes ../dishes
|
@python ../bin/ksflatten-relative ../recipes ../dishes
|
||||||
@@ -52,5 +39,3 @@ clean-dishes:
|
|||||||
clean:
|
clean:
|
||||||
rm -f ../recipes/*.cfg
|
rm -f ../recipes/*.cfg
|
||||||
@echo "Generated recipes removed. Edit recipes_manifest.yaml and run 'make generate-recipes' to regenerate. Run 'make clean-dishes' to remove flattened dishes."
|
@echo "Generated recipes removed. Edit recipes_manifest.yaml and run 'make generate-recipes' to regenerate. Run 'make clean-dishes' to remove flattened dishes."
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -396,7 +396,7 @@ def generate_from_manifest(args: argparse.Namespace, generator: RecipeGenerator)
|
|||||||
|
|
||||||
# Generate all recipes from the manifest
|
# Generate all recipes from the manifest
|
||||||
for recipe_config in manifest.get('recipes', []):
|
for recipe_config in manifest.get('recipes', []):
|
||||||
recipe_type = recipe_config['name']
|
recipe_type = recipe_config.get('recipe_type', recipe_config['name'])
|
||||||
if recipe_type not in generator.templates:
|
if recipe_type not in generator.templates:
|
||||||
print(f"Error: Unknown recipe type in manifest: {recipe_type}", file=sys.stderr)
|
print(f"Error: Unknown recipe type in manifest: {recipe_type}", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@@ -411,12 +411,8 @@ def generate_from_manifest(args: argparse.Namespace, generator: RecipeGenerator)
|
|||||||
# Extract version and other modifiers from variant
|
# Extract version and other modifiers from variant
|
||||||
version = variant['version']
|
version = variant['version']
|
||||||
modifiers = {k: v for k, v in variant.items() if k not in ['name', 'version']}
|
modifiers = {k: v for k, v in variant.items() if k not in ['name', 'version']}
|
||||||
variant_subname = variant.get('name', '')
|
modifiers = {k: v for k, v in variant.items() if k not in ['name', 'version']}
|
||||||
|
# name kept for manifest organization only, not passed to generator
|
||||||
# Add variant name as modifier if present
|
|
||||||
if variant_subname:
|
|
||||||
modifiers['variant_type'] = variant_subname
|
|
||||||
modifiers['variant_subname'] = variant_subname
|
|
||||||
|
|
||||||
# Generate the recipe content
|
# Generate the recipe content
|
||||||
content = generator.generate(recipe_type, version, **modifiers)
|
content = generator.generate(recipe_type, version, **modifiers)
|
||||||
@@ -472,7 +468,7 @@ def generate_single(args: argparse.Namespace, generator: RecipeGenerator) -> Non
|
|||||||
# Build modifiers dictionary from command-line arguments
|
# Build modifiers dictionary from command-line arguments
|
||||||
# Only include non-default values to keep filenames clean
|
# Only include non-default values to keep filenames clean
|
||||||
modifiers = {
|
modifiers = {
|
||||||
'variant_type': 'desktop',
|
|
||||||
'desktop': args.desktop if args.desktop else None,
|
'desktop': args.desktop if args.desktop else None,
|
||||||
'storage': args.storage if args.storage != 'standard' else None,
|
'storage': args.storage if args.storage != 'standard' else None,
|
||||||
'security': args.security if args.security != 'secure' else None,
|
'security': args.security if args.security != 'secure' else None,
|
||||||
|
|||||||
@@ -494,12 +494,6 @@ class RecipeGenerator:
|
|||||||
Returns:
|
Returns:
|
||||||
Filename string ending in .cfg
|
Filename string ending in .cfg
|
||||||
"""
|
"""
|
||||||
# Extract variant subname if present
|
|
||||||
# Used to distinguish between desktop/server/hypervisor variants
|
|
||||||
variant_subname = modifiers.get('variant_subname', '')
|
|
||||||
if not variant_subname:
|
|
||||||
variant_subname = modifiers.get('variant_type', '')
|
|
||||||
|
|
||||||
# Build base parts - start with recipe type
|
# Build base parts - start with recipe type
|
||||||
parts = [recipe_type.replace('_', '-')]
|
parts = [recipe_type.replace('_', '-')]
|
||||||
|
|
||||||
@@ -511,10 +505,13 @@ class RecipeGenerator:
|
|||||||
elif guest_agents is False:
|
elif guest_agents is False:
|
||||||
parts.append('bare-metal')
|
parts.append('bare-metal')
|
||||||
|
|
||||||
# Add variant_subname for install variants
|
# Add hypervisor indicator if present
|
||||||
# Only include recognized variant types
|
if modifiers.get('hypervisor'):
|
||||||
if variant_subname and variant_subname in ['desktop', 'server', 'hypervisor', 'hypervisor-desktop']:
|
if modifiers.get('hypervisor') in ['base', 'desktop']:
|
||||||
parts.append(variant_subname)
|
if modifiers.get('desktop'):
|
||||||
|
parts.append('hypervisor-desktop')
|
||||||
|
else:
|
||||||
|
parts.append('hypervisor')
|
||||||
|
|
||||||
# Add hypervisor_type suffix
|
# Add hypervisor_type suffix
|
||||||
# For hypervisors, include the type (kvm, xen, etc.)
|
# For hypervisors, include the type (kvm, xen, etc.)
|
||||||
@@ -529,10 +526,9 @@ class RecipeGenerator:
|
|||||||
# Single hypervisor type
|
# Single hypervisor type
|
||||||
parts.append(ht)
|
parts.append(ht)
|
||||||
|
|
||||||
# Add desktop (non-GNOME only, since GNOME is default)
|
# Add desktop
|
||||||
# GNOME is the default desktop, so we only note alternatives
|
|
||||||
desktop = self._get_modifier(modifiers, 'desktop')
|
desktop = self._get_modifier(modifiers, 'desktop')
|
||||||
if desktop and desktop != 'gnome':
|
if desktop:
|
||||||
parts.append(desktop)
|
parts.append(desktop)
|
||||||
|
|
||||||
# Add security suffix (devel only, since secure is default)
|
# Add security suffix (devel only, since secure is default)
|
||||||
@@ -551,12 +547,15 @@ class RecipeGenerator:
|
|||||||
# Hardware support detection is optional
|
# Hardware support detection is optional
|
||||||
hardware_support = self._get_modifier(modifiers, 'hardware_support')
|
hardware_support = self._get_modifier(modifiers, 'hardware_support')
|
||||||
if hardware_support is True:
|
if hardware_support is True:
|
||||||
parts.append('hw')
|
parts.append('hardware-support')
|
||||||
|
|
||||||
# Add initial_setup suffix (non-server values)
|
# Add initial_setup suffix (non-server values)
|
||||||
# Server is default, other setup types get noted
|
# Server is default, other setup types get noted
|
||||||
initial_setup = self._get_modifier(modifiers, 'initial_setup')
|
initial_setup = self._get_modifier(modifiers, 'initial_setup')
|
||||||
if initial_setup and initial_setup != 'server':
|
if initial_setup == 'server':
|
||||||
|
# Server is the default for non-desktop, non-hypervisor
|
||||||
|
parts.append('server')
|
||||||
|
elif initial_setup and initial_setup != 'server':
|
||||||
parts.append(f'{initial_setup}-setup')
|
parts.append(f'{initial_setup}-setup')
|
||||||
|
|
||||||
# Add bootloader suffix (systemd-boot only)
|
# Add bootloader suffix (systemd-boot only)
|
||||||
|
|||||||
@@ -9,24 +9,17 @@ templates:
|
|||||||
base: core
|
base: core
|
||||||
required:
|
required:
|
||||||
- core: ingredients/core/base.ks
|
- core: ingredients/core/base.ks
|
||||||
- version: ingredients/repo/fedora-43-mirrors.ks
|
- { path: ingredients/repo/fedora-43-mirrors.ks, replaceable: true }
|
||||||
- storage: ingredients/storage/standard.ks
|
- { path: ingredients/storage/standard.ks, replaceable: true }
|
||||||
- bootloader: ingredients/bootloader/grub.ks
|
- { path: ingredients/bootloader/grub.ks, replaceable: true }
|
||||||
- locale: ingredients/core/locale.ks
|
- ingredients/core/locale.ks
|
||||||
- services: ingredients/core/services.ks
|
- ingredients/core/services.ks
|
||||||
- network: ingredients/core/network.ks
|
- ingredients/core/network.ks
|
||||||
- packages: ingredients/packages/core-group.ks
|
- ingredients/packages/core-group.ks
|
||||||
- fedora-remix: ingredients/packages/fedora-remix.ks
|
- ingredients/packages/fedora-remix.ks
|
||||||
- hand-picked: ingredients/packages/hand-picked.ks
|
- ingredients/packages/hand-picked.ks
|
||||||
- security: ingredients/core/security/enabled.ks
|
- { path: ingredients/core/security/enabled.ks, replaceable: true }
|
||||||
- initial-setup: ingredients/initial-setup/server/config.ks
|
- { path: ingredients/initial-setup/server/config.ks, replaceable: true }
|
||||||
optional:
|
|
||||||
hardware-support: ingredients/packages/hardware-support.ks
|
|
||||||
guest-agents: ingredients/guest-agents/base.ks
|
|
||||||
variant_type:
|
|
||||||
desktop:
|
|
||||||
server:
|
|
||||||
hypervisor:
|
|
||||||
modifiers:
|
modifiers:
|
||||||
version:
|
version:
|
||||||
"43": ingredients/repo/fedora-43-mirrors.ks
|
"43": ingredients/repo/fedora-43-mirrors.ks
|
||||||
@@ -59,11 +52,14 @@ templates:
|
|||||||
- ingredients/hypervisor/base/services.ks
|
- ingredients/hypervisor/base/services.ks
|
||||||
- ingredients/hypervisor/base/post-scripts.ks
|
- ingredients/hypervisor/base/post-scripts.ks
|
||||||
desktop:
|
desktop:
|
||||||
- ingredients/packages/virtual-machine-manager/packages.ks
|
- ingredients/packages/virtual-machine-manager/packages.ks
|
||||||
- ingredients/packages/virtual-machine-manager/post-scripts.ks
|
- ingredients/packages/virtual-machine-manager/post-scripts.ks
|
||||||
bootloader:
|
bootloader:
|
||||||
grub: ingredients/bootloader/grub.ks
|
grub: ingredients/bootloader/grub.ks
|
||||||
systemd-boot: ingredients/bootloader/systemd-boot.ks
|
systemd-boot: ingredients/bootloader/systemd-boot.ks
|
||||||
|
optional:
|
||||||
|
hardware-support: ingredients/packages/hardware-support.ks
|
||||||
|
guest-agents: ingredients/guest-agents/base.ks
|
||||||
|
|
||||||
# Live recipe - for live-desktop or live-server
|
# Live recipe - for live-desktop or live-server
|
||||||
live:
|
live:
|
||||||
@@ -71,26 +67,16 @@ templates:
|
|||||||
base: live-core
|
base: live-core
|
||||||
required:
|
required:
|
||||||
- live-core: ingredients/live/core/base.ks
|
- live-core: ingredients/live/core/base.ks
|
||||||
- version: ingredients/repo/fedora-43-mirrors.ks
|
- { path: ingredients/repo/fedora-43-mirrors.ks, replaceable: true }
|
||||||
- storage: ingredients/live/core/storage.ks
|
- { path: ingredients/live/core/storage.ks, replaceable: true }
|
||||||
- bootloader: ingredients/live/core/bootloader/grub.ks
|
- { path: ingredients/live/core/bootloader/grub.ks, replaceable: true }
|
||||||
- locale: ingredients/core/locale.ks
|
- ingredients/core/locale.ks
|
||||||
- services: ingredients/core/services.ks
|
- ingredients/core/services.ks
|
||||||
- network: ingredients/core/network.ks
|
- ingredients/core/network.ks
|
||||||
- packages: ingredients/live/core/packages.ks
|
- ingredients/live/core/packages.ks
|
||||||
- post: ingredients/live/post/base.ks
|
- ingredients/live/post/base.ks
|
||||||
- session: ingredients/live/post/session.ks
|
- ingredients/live/post/session.ks
|
||||||
- rpmfusion-nonfree: ingredients/repo/rpmfusion-nonfree.ks
|
- ingredients/repo/rpmfusion-nonfree.ks
|
||||||
optional:
|
|
||||||
variant_type:
|
|
||||||
desktop:
|
|
||||||
server:
|
|
||||||
hardware-support: ingredients/packages/hardware-support.ks
|
|
||||||
guest-agents: ingredients/guest-agents/base.ks
|
|
||||||
hypervisor: ingredients/live/hypervisor.ks
|
|
||||||
security:
|
|
||||||
secure: ingredients/core/security/enabled.ks
|
|
||||||
"off": ingredients/core/security/disabled.ks
|
|
||||||
modifiers:
|
modifiers:
|
||||||
version:
|
version:
|
||||||
"43": ingredients/repo/fedora-43-mirrors.ks
|
"43": ingredients/repo/fedora-43-mirrors.ks
|
||||||
@@ -101,3 +87,10 @@ templates:
|
|||||||
bootloader:
|
bootloader:
|
||||||
grub: ingredients/live/core/bootloader/grub.ks
|
grub: ingredients/live/core/bootloader/grub.ks
|
||||||
systemd-boot: ingredients/live/core/bootloader/systemd-boot.ks
|
systemd-boot: ingredients/live/core/bootloader/systemd-boot.ks
|
||||||
|
optional:
|
||||||
|
hardware-support: ingredients/packages/hardware-support.ks
|
||||||
|
guest-agents: ingredients/guest-agents/base.ks
|
||||||
|
hypervisor: ingredients/live/hypervisor.ks
|
||||||
|
security:
|
||||||
|
secure: ingredients/core/security/enabled.ks
|
||||||
|
"off": ingredients/core/security/disabled.ks
|
||||||
|
|||||||
@@ -11,15 +11,15 @@
|
|||||||
# Example: version: ["43", "rawhide"] + storage: ["standard", "encrypted"]
|
# Example: version: ["43", "rawhide"] + storage: ["standard", "encrypted"]
|
||||||
# creates 4 variants: (43,standard), (43,encrypted), (rawhide,standard), (rawhide,encrypted)
|
# creates 4 variants: (43,standard), (43,encrypted), (rawhide,standard), (rawhide,encrypted)
|
||||||
#
|
#
|
||||||
# NOTE: Boolean modifiers now generate unique filenames regardless of value (True/False).
|
# NOTE: The 'name' field is for organization only and doesn't affect generated filenames.
|
||||||
# Each variant combination produces a distinct filename with appropriate suffixes.
|
# The recipe type is always 'install' or 'live' from recipe_templates.yaml
|
||||||
|
|
||||||
recipes:
|
recipes:
|
||||||
# Install variants - desktop
|
# Install desktop variants
|
||||||
- name: install
|
- name: desktop
|
||||||
|
recipe_type: install
|
||||||
variants:
|
variants:
|
||||||
- name: desktop
|
- version: ["43", "rawhide"]
|
||||||
version: ["43", "rawhide"]
|
|
||||||
desktop: gnome
|
desktop: gnome
|
||||||
storage: ["standard", "encrypted"]
|
storage: ["standard", "encrypted"]
|
||||||
bootloader: grub
|
bootloader: grub
|
||||||
@@ -28,11 +28,11 @@ recipes:
|
|||||||
initial-setup: server
|
initial-setup: server
|
||||||
security: secure
|
security: secure
|
||||||
|
|
||||||
# Install variants - server
|
# Install server variants
|
||||||
- name: install
|
- name: server
|
||||||
|
recipe_type: install
|
||||||
variants:
|
variants:
|
||||||
- name: server
|
- version: ["43", "rawhide"]
|
||||||
version: ["43", "rawhide"]
|
|
||||||
storage: standard
|
storage: standard
|
||||||
bootloader: grub
|
bootloader: grub
|
||||||
hardware-support: false
|
hardware-support: false
|
||||||
@@ -40,11 +40,11 @@ recipes:
|
|||||||
initial-setup: server
|
initial-setup: server
|
||||||
security: secure
|
security: secure
|
||||||
|
|
||||||
# Install variants - server hypervisor
|
# Install hypervisor variants
|
||||||
- name: install
|
- name: hypervisor
|
||||||
|
recipe_type: install
|
||||||
variants:
|
variants:
|
||||||
- name: hypervisor
|
- version: 43
|
||||||
version: 43
|
|
||||||
storage: standard
|
storage: standard
|
||||||
bootloader: grub
|
bootloader: grub
|
||||||
hardware-support: true
|
hardware-support: true
|
||||||
@@ -54,11 +54,11 @@ recipes:
|
|||||||
initial-setup: server
|
initial-setup: server
|
||||||
security: secure
|
security: secure
|
||||||
|
|
||||||
# Install variants - desktop-hypervisor
|
# Install desktop-hypervisor variants
|
||||||
- name: install
|
- name: desktop-hypervisor
|
||||||
|
recipe_type: install
|
||||||
variants:
|
variants:
|
||||||
- name: hypervisor-desktop
|
- version: 43
|
||||||
version: 43
|
|
||||||
desktop: gnome
|
desktop: gnome
|
||||||
storage: standard
|
storage: standard
|
||||||
bootloader: grub
|
bootloader: grub
|
||||||
@@ -69,18 +69,18 @@ recipes:
|
|||||||
initial-setup: server
|
initial-setup: server
|
||||||
security: secure
|
security: secure
|
||||||
|
|
||||||
# Live variants - desktop
|
# Live desktop variants
|
||||||
- name: live
|
- name: desktop
|
||||||
|
recipe_type: live
|
||||||
variants:
|
variants:
|
||||||
- name: desktop
|
- version: 43
|
||||||
version: 43
|
|
||||||
hardware-support: true
|
hardware-support: true
|
||||||
guest-agents: false
|
guest-agents: false
|
||||||
|
|
||||||
# Live variants - server
|
# Live server variants
|
||||||
- name: live
|
- name: server
|
||||||
|
recipe_type: live
|
||||||
variants:
|
variants:
|
||||||
- name: server
|
- version: 43
|
||||||
version: 43
|
|
||||||
hardware-support: true
|
hardware-support: true
|
||||||
guest-agents: false
|
guest-agents: false
|
||||||
|
|||||||
@@ -1,3 +1,2 @@
|
|||||||
PyYAML>=6.0
|
PyYAML>=6.0
|
||||||
pytest>=7.0
|
|
||||||
pykickstart>=1.99
|
pykickstart>=1.99
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
# __ ____ ____ _____
|
|
||||||
# ____ / /_ __ __/ / /___ ____ ___ ___ / __ \/ ___/
|
|
||||||
# / __ \/ __ \/ / / / / / __ \/ __ `__ \/ _ \ / / / /\__ \
|
|
||||||
# / /_/ / / / / /_/ / / / /_/ / / / / / / __/ / /_/ /___/ /
|
|
||||||
# / .___/_/ /_/\__, /_/_/\____/_/ /_/ /_/\___/ \____//____/
|
|
||||||
# /_/ /____/
|
|
||||||
|
|
||||||
# A live recipe for live-desktop or live-server
|
|
||||||
|
|
||||||
%include ingredients/live/core/base.ks
|
|
||||||
%include ingredients/repo/fedora-43-mirrors.ks
|
|
||||||
%include ingredients/live/core/storage.ks
|
|
||||||
%include ingredients/live/core/bootloader/grub.ks
|
|
||||||
%include ingredients/core/locale.ks
|
|
||||||
%include ingredients/core/services.ks
|
|
||||||
%include ingredients/core/network.ks
|
|
||||||
%include ingredients/live/core/packages.ks
|
|
||||||
%include ingredients/live/post/base.ks
|
|
||||||
%include ingredients/live/post/session.ks
|
|
||||||
%include ingredients/repo/rpmfusion-nonfree.ks
|
|
||||||
Binary file not shown.
@@ -1,25 +0,0 @@
|
|||||||
# Phyllome OS Recipe Generator Test Container
|
|
||||||
|
|
||||||
FROM fedora:43
|
|
||||||
LABEL maintainer='Phyllome OS Team'
|
|
||||||
|
|
||||||
# Install minimal test dependencies
|
|
||||||
RUN dnf -y install \
|
|
||||||
pykickstart \
|
|
||||||
python3-pytest \
|
|
||||||
python3-pyyaml \
|
|
||||||
make \
|
|
||||||
git \
|
|
||||||
&& dnf clean all
|
|
||||||
|
|
||||||
# Set working directory
|
|
||||||
WORKDIR /phyllomeos
|
|
||||||
|
|
||||||
# Copy project files
|
|
||||||
COPY . /phyllomeos/
|
|
||||||
|
|
||||||
# Install Python dependencies
|
|
||||||
RUN pip install --no-cache-dir PyYAML pytest
|
|
||||||
|
|
||||||
# Run tests by default
|
|
||||||
CMD ["bash", "-c", "cd /phyllomeos && pytest tests/ -v"]
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
# Phyllome OS Recipe Generator Test Container
|
|
||||||
|
|
||||||
Minimal containerized testing environment for kickstart recipe validation.
|
|
||||||
|
|
||||||
## Build
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd /home/lukas/Code/virt/phyllomeos
|
|
||||||
|
|
||||||
podman build -t phyllo/test-runner tests/container/
|
|
||||||
# or: docker build -t phyllo/test-runner tests/container/
|
|
||||||
```
|
|
||||||
|
|
||||||
## Run Tests
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Run all tests (unit + integration + golden masters)
|
|
||||||
podman run --rm -v .:/phyllomeos:ro phyllo/test-runner
|
|
||||||
|
|
||||||
# Run specific test file
|
|
||||||
podman run --rm -v .:/phyllomeos:ro phyllo/test-runner pytest tests/integration/test_ingredients.py -v
|
|
||||||
|
|
||||||
# Interactive mode for debugging
|
|
||||||
podman run -it --rm -v .:/phyllomeos phyllo/test-runner bash
|
|
||||||
```
|
|
||||||
|
|
||||||
## Test Types
|
|
||||||
|
|
||||||
### Unit Tests
|
|
||||||
- **Location:** `tests/test_recipe_generator.py`
|
|
||||||
- **Count:** 36 tests
|
|
||||||
- **Description:** Tests for recipe generator functionality (template loading, validation, version extraction)
|
|
||||||
|
|
||||||
### Fragment Validation Tests
|
|
||||||
- **Location:** `tests/integration/test_ingredients.py`
|
|
||||||
- **Count:** ~15 tests
|
|
||||||
- **Description:** Validates all 54 ingredients with pykickstart, checks section structure
|
|
||||||
|
|
||||||
### Recipe Composition Tests
|
|
||||||
- **Location:** `tests/integration/test_recipe_composition.py`
|
|
||||||
- **Count:** ~10 tests
|
|
||||||
- **Description:** Tests recipe generation, validates all 16 manifest variants
|
|
||||||
|
|
||||||
### Semantic Validation Tests
|
|
||||||
- **Location:** `tests/integration/test_semantic_validation.py`
|
|
||||||
- **Count:** ~10 tests
|
|
||||||
- **Description:** pykickstart semantic validation, deprecated command detection
|
|
||||||
|
|
||||||
### Golden Master Tests
|
|
||||||
- **Location:** `tests/integration/test_golden_masters.py`
|
|
||||||
- **Count:** ~5 tests
|
|
||||||
- **Description:** Regression tests comparing generated recipes against expected outputs
|
|
||||||
|
|
||||||
## Test Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
tests/
|
|
||||||
├── test_recipe_generator.py # Unit tests (36 tests)
|
|
||||||
├── integration/
|
|
||||||
│ ├── test_ingredients.py # Fragment validation (~15 tests)
|
|
||||||
│ ├── test_recipe_composition.py # Recipe generation (~10 tests)
|
|
||||||
│ ├── test_semantic_validation.py # pykickstart semantic (~10 tests)
|
|
||||||
│ ├── test_golden_masters.py # Regression tests (~5 tests)
|
|
||||||
│ └── conftest.py # Pytest fixtures
|
|
||||||
├── fixtures/
|
|
||||||
│ ├── expected_recipes/ # 5 golden master files
|
|
||||||
│ └── sample_ingredients/ # Test fragment samples
|
|
||||||
└── container/
|
|
||||||
├── Containerfile # Test runner container definition
|
|
||||||
├── run-tests.sh # Test entrypoint script
|
|
||||||
└── README.md # This file
|
|
||||||
```
|
|
||||||
|
|
||||||
## Container Contents
|
|
||||||
|
|
||||||
The test runner container includes:
|
|
||||||
|
|
||||||
- **OS:** Fedora 43
|
|
||||||
- **Python packages:**
|
|
||||||
- `pykickstart` - Kickstart parsing and validation
|
|
||||||
- `pytest` - Test framework
|
|
||||||
- `PyYAML` - YAML parsing
|
|
||||||
- **System tools:**
|
|
||||||
- `make` - Build automation
|
|
||||||
- `git` - Version control
|
|
||||||
- `coreutils` - Basic utilities
|
|
||||||
|
|
||||||
## Adding New Tests
|
|
||||||
|
|
||||||
1. Add test file to `tests/integration/`
|
|
||||||
2. Follow naming convention: `test_*.py`
|
|
||||||
3. Use pytest fixtures from `conftest.py`
|
|
||||||
4. Run tests in container to verify
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
### Container won't start
|
|
||||||
```bash
|
|
||||||
# Check if container builds
|
|
||||||
podman build tests/container/
|
|
||||||
|
|
||||||
# Run with verbose output
|
|
||||||
podman run --rm -v .:/phyllomeos:ro -e PYTEST_VERBOSITY=2 phyllo/test-runner
|
|
||||||
```
|
|
||||||
|
|
||||||
### Tests failing inside container
|
|
||||||
```bash
|
|
||||||
# Get interactive shell
|
|
||||||
podman run -it --rm -v .:/phyllomeos phyllo/test-runner bash
|
|
||||||
|
|
||||||
# Run tests manually
|
|
||||||
cd /phyllomeos
|
|
||||||
pytest tests/integration/test_ingredients.py -v
|
|
||||||
```
|
|
||||||
|
|
||||||
### Permission denied errors
|
|
||||||
```bash
|
|
||||||
# Run with security options (for rootless podman)
|
|
||||||
podman run --rm --security-opt label=disable -v .:/phyllomeos:ro phyllo/test-runner
|
|
||||||
```
|
|
||||||
|
|
||||||
## CI/CD Integration
|
|
||||||
|
|
||||||
This container will be used in Gitea Actions workflows for:
|
|
||||||
- Pull request validation
|
|
||||||
- Main branch testing
|
|
||||||
- Automated recipe generation checks
|
|
||||||
|
|
||||||
See `.gitea/workflows/` for workflow definitions.
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Run all tests inside the container environment
|
|
||||||
# Usage: podman run --rm -v .:/phyllomeos:ro phyllo/test-runner
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
echo "============================================="
|
|
||||||
echo " Phyllome OS Recipe Generator Test Suite"
|
|
||||||
echo "============================================="
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Navigate to project root
|
|
||||||
cd /phyllomeos
|
|
||||||
|
|
||||||
echo "[1/3] Running unit tests (test_recipe_generator.py)..."
|
|
||||||
echo "----------------------------------------"
|
|
||||||
python3 -m pytest tests/test_recipe_generator.py -v
|
|
||||||
echo "✓ Unit tests passed!"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
echo "[2/3] Running integration tests..."
|
|
||||||
echo "----------------------------------------"
|
|
||||||
python3 -m pytest tests/integration/ -v
|
|
||||||
echo "✓ Integration tests passed!"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
echo "[3/3] Validating generated recipes..."
|
|
||||||
echo "----------------------------------------"
|
|
||||||
cd recipe-generator
|
|
||||||
python3 generate_recipe.py --validate ../recipes/*.cfg --strict
|
|
||||||
echo "✓ Recipe validation passed!"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
echo "============================================="
|
|
||||||
echo " ALL TESTS PASSED!"
|
|
||||||
echo "============================================="
|
|
||||||
echo ""
|
|
||||||
echo "Summary:"
|
|
||||||
echo " - Unit tests: 36 tests (test_recipe_generator.py)"
|
|
||||||
echo " - Integration tests: Fragment validation, recipe composition, golden masters"
|
|
||||||
echo " - Fragment validation: 54 .ks files checked"
|
|
||||||
echo " - Recipe validation: All 16 manifest variants generated and validated"
|
|
||||||
echo ""
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
# __ ____ ____ _____
|
|
||||||
# ____ / /_ __ __/ / /___ ____ ___ ___ / __ \/ ___/
|
|
||||||
# / __ \/ __ \/ / / / / / __ \/ __ `__ \/ _ \ / / / /\__ \
|
|
||||||
# / /_/ / / / / /_/ / / / /_/ / / / / / / __/ / /_/ /___/ /
|
|
||||||
# / .___/_/ /_/\__, /_/_/\____/_/ /_/ /_/\___/ \____//____/
|
|
||||||
# /_/ /____/
|
|
||||||
|
|
||||||
# A recipe for a desktop hypervisor
|
|
||||||
|
|
||||||
%include ingredients/core/base.ks
|
|
||||||
%include ingredients/storage/standard.ks
|
|
||||||
%include ingredients/bootloader/grub.ks
|
|
||||||
%include ingredients/core/locale.ks
|
|
||||||
%include ingredients/core/services.ks
|
|
||||||
%include ingredients/core/network.ks
|
|
||||||
%include ingredients/packages/core-group.ks
|
|
||||||
%include ingredients/packages/fedora-remix.ks
|
|
||||||
%include ingredients/packages/hand-picked.ks
|
|
||||||
%include ingredients/core/security/enabled.ks
|
|
||||||
%include ingredients/packages/virtual-machine-manager/packages.ks
|
|
||||||
%include ingredients/packages/virtual-machine-manager/post-scripts.ks
|
|
||||||
%include ingredients/initial-setup/server/config.ks
|
|
||||||
%include ingredients/hypervisor/intelcpu.ks
|
|
||||||
%include ingredients/repo/rawhide-mirrors.ks
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
# __ ____ ____ _____
|
|
||||||
# ____ / /_ __ __/ / /___ ____ ___ ___ / __ \/ ___/
|
|
||||||
# / __ \/ __ \/ / / / / / __ \/ __ `__ \/ _ \ / / / /\__ \
|
|
||||||
# / /_/ / / / / /_/ / / / /_/ / / / / / / __/ / /_/ /___/ /
|
|
||||||
# / .___/_/ /_/\__, /_/_/\____/_/ /_/ /_/\___/ \____//____/
|
|
||||||
# /_/ /____/
|
|
||||||
|
|
||||||
# A recipe for a desktop hypervisor
|
|
||||||
|
|
||||||
%include ingredients/core/base.ks
|
|
||||||
%include ingredients/storage/standard.ks
|
|
||||||
%include ingredients/bootloader/grub.ks
|
|
||||||
%include ingredients/core/locale.ks
|
|
||||||
%include ingredients/core/services.ks
|
|
||||||
%include ingredients/core/network.ks
|
|
||||||
%include ingredients/packages/core-group.ks
|
|
||||||
%include ingredients/packages/fedora-remix.ks
|
|
||||||
%include ingredients/packages/hand-picked.ks
|
|
||||||
%include ingredients/core/security/enabled.ks
|
|
||||||
%include ingredients/packages/virtual-machine-manager/packages.ks
|
|
||||||
%include ingredients/packages/virtual-machine-manager/post-scripts.ks
|
|
||||||
%include ingredients/initial-setup/server/config.ks
|
|
||||||
%include ingredients/hypervisor/intelcpu.ks
|
|
||||||
%include ingredients/repo/rawhide-mirrors.ks
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
# __ ____ ____ _____
|
|
||||||
# ____ / /_ __ __/ / /___ ____ ___ ___ / __ \/ ___/
|
|
||||||
# / __ \/ __ \/ / / / / / __ \/ __ `__ \/ _ \ / / / /\__ \
|
|
||||||
# / /_/ / / / / /_/ / / / /_/ / / / / / / __/ / /_/ /___/ /
|
|
||||||
# / .___/_/ /_/\__, /_/_/\____/_/ /_/ /_/\___/ \____//____/
|
|
||||||
# /_/ /____/
|
|
||||||
|
|
||||||
# A recipe for a desktop hypervisor
|
|
||||||
|
|
||||||
%include ingredients/core/base.ks
|
|
||||||
%include ingredients/storage/standard.ks
|
|
||||||
%include ingredients/bootloader/grub.ks
|
|
||||||
%include ingredients/core/locale.ks
|
|
||||||
%include ingredients/core/services.ks
|
|
||||||
%include ingredients/core/network.ks
|
|
||||||
%include ingredients/packages/core-group.ks
|
|
||||||
%include ingredients/packages/fedora-remix.ks
|
|
||||||
%include ingredients/packages/hand-picked.ks
|
|
||||||
%include ingredients/core/security/enabled.ks
|
|
||||||
%include ingredients/packages/virtual-machine-manager/packages.ks
|
|
||||||
%include ingredients/packages/virtual-machine-manager/post-scripts.ks
|
|
||||||
%include ingredients/initial-setup/server/config.ks
|
|
||||||
%include ingredients/hypervisor/intelcpu.ks
|
|
||||||
%include ingredients/repo/rawhide-mirrors.ks
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
# __ ____ ____ _____
|
|
||||||
# ____ / /_ __ __/ / /___ ____ ___ ___ / __ \/ ___/
|
|
||||||
# / __ \/ __ \/ / / / / / __ \/ __ `__ \/ _ \ / / / /\__ \
|
|
||||||
# / /_/ / / / / /_/ / / / /_/ / / / / / / __/ / /_/ /___/ /
|
|
||||||
# / .___/_/ /_/\__, /_/_/\____/_/ /_/ /_/\___/ \____//____/
|
|
||||||
# /_/ /____/
|
|
||||||
|
|
||||||
# A recipe for a live desktop
|
|
||||||
|
|
||||||
%include ingredients/shared/live/core/base.ks
|
|
||||||
%include ingredients/shared/live/core/storage.ks
|
|
||||||
%include ingredients/platform/generic-rawhide/bootloader/grub.ks
|
|
||||||
%include ingredients/shared/core/locale.ks
|
|
||||||
%include ingredients/shared/core/services.ks
|
|
||||||
%include ingredients/shared/core/network.ks
|
|
||||||
%include ingredients/shared/live/core/packages.ks
|
|
||||||
%include ingredients/shared/live/post/base.ks
|
|
||||||
%include ingredients/shared/live/post/session.ks
|
|
||||||
%include ingredients/shared/initial-setup/desktop/config.ks
|
|
||||||
%include ingredients/shared/desktop/gnome/config.ks
|
|
||||||
%include ingredients/shared/desktop/gnome/packages.ks
|
|
||||||
%include ingredients/shared/desktop/gnome/post-scripts.ks
|
|
||||||
%include ingredients/platform/generic-rawhide/repo/rawhide-mirrors.ks
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
# __ ____ ____ _____
|
|
||||||
# ____ / /_ __ __/ / /___ ____ ___ ___ / __ \/ ___/
|
|
||||||
# / __ \/ __ \/ / / / / / __ \/ __ `__ \/ _ \ / / / /\__ \
|
|
||||||
# / /_/ / / / / /_/ / / / /_/ / / / / / / __/ / /_/ /___/ /
|
|
||||||
# / .___/_/ /_/\__, /_/_/\____/_/ /_/ /_/\___/ \____//____/
|
|
||||||
# /_/ /____/
|
|
||||||
|
|
||||||
# A recipe for a live server
|
|
||||||
|
|
||||||
%include ingredients/shared/live/core/base.ks
|
|
||||||
%include ingredients/shared/live/core/storage.ks
|
|
||||||
%include ingredients/platform/generic-rawhide/bootloader/grub.ks
|
|
||||||
%include ingredients/shared/core/locale.ks
|
|
||||||
%include ingredients/shared/core/services.ks
|
|
||||||
%include ingredients/shared/core/network.ks
|
|
||||||
%include ingredients/shared/live/core/packages.ks
|
|
||||||
%include ingredients/shared/live/post/base.ks
|
|
||||||
%include ingredients/shared/live/post/session.ks
|
|
||||||
%include ingredients/shared/initial-setup/server/config.ks
|
|
||||||
%include ingredients/platform/generic-rawhide/repo/rawhide-mirrors.ks
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
# __ ____ ____ _____
|
|
||||||
# ____ / /_ __ __/ / /___ ____ ___ ___ / __ \/ ___/
|
|
||||||
# / __ \/ __ \/ / / / / / __ \/ __ `__ \/ _ \ / / / /\__ \
|
|
||||||
# / /_/ / / / / /_/ / / / /_/ / / / / / / __/ / /_/ /___/ /
|
|
||||||
# / .___/_/ /_/\__, /_/_/\____/_/ /_/ /_/\___/ \____//____/
|
|
||||||
# /_/ /____/
|
|
||||||
|
|
||||||
# A recipe for a virtual desktop
|
|
||||||
|
|
||||||
%include ingredients/shared/core/base.ks
|
|
||||||
%include ingredients/shared/storage/standard.ks
|
|
||||||
%include ingredients/platform/generic-43/bootloader/grub.ks
|
|
||||||
%include ingredients/shared/core/locale.ks
|
|
||||||
%include ingredients/shared/core/services.ks
|
|
||||||
%include ingredients/shared/core/network.ks
|
|
||||||
%include ingredients/shared/packages/core-group.ks
|
|
||||||
%include ingredients/shared/packages/fedora-remix.ks
|
|
||||||
%include ingredients/shared/packages/hand-picked.ks
|
|
||||||
%include ingredients/shared/initial-setup/server/config.ks
|
|
||||||
%include ingredients/platform/generic-43/repo/fedora-mirrors.ks
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
# __ ____ ____ _____
|
|
||||||
# ____ / /_ __ __/ / /___ ____ ___ ___ / __ \/ ___/
|
|
||||||
# / __ \/ __ \/ / / / / / __ \/ __ `__ \/ _ \ / / / /\__ \
|
|
||||||
# / /_/ / / / / /_/ / / / /_/ / / / / / / __/ / /_/ /___/ /
|
|
||||||
# / .___/_/ /_/\__, /_/_/\____/_/ /_/ /_/\___/ \____//____/
|
|
||||||
# /_/ /____/
|
|
||||||
|
|
||||||
# A recipe for a virtual server
|
|
||||||
|
|
||||||
%include ingredients/shared/core/base.ks
|
|
||||||
%include ingredients/shared/storage/standard.ks
|
|
||||||
%include ingredients/platform/generic-43/bootloader/grub.ks
|
|
||||||
%include ingredients/shared/core/locale.ks
|
|
||||||
%include ingredients/shared/core/services.ks
|
|
||||||
%include ingredients/shared/core/network.ks
|
|
||||||
%include ingredients/shared/packages/core-group.ks
|
|
||||||
%include ingredients/shared/packages/fedora-remix.ks
|
|
||||||
%include ingredients/shared/packages/hand-picked.ks
|
|
||||||
%include ingredients/shared/initial-setup/server/config.ks
|
|
||||||
%include ingredients/platform/generic-rawhide/repo/rawhide-mirrors.ks
|
|
||||||
Binary file not shown.
Binary file not shown.
@@ -1,50 +0,0 @@
|
|||||||
"""Pytest fixtures and shared utilities for Phyllome OS integration tests."""
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
from pathlib import Path
|
|
||||||
import sys
|
|
||||||
|
|
||||||
# Find project root (3 levels up from integration tests)
|
|
||||||
PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent
|
|
||||||
SCRIPTS_DIR = PROJECT_ROOT / 'recipe-generator'
|
|
||||||
sys.path.insert(0, str(SCRIPTS_DIR))
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def generator():
|
|
||||||
"""Create RecipeGenerator instance."""
|
|
||||||
from recipe_generator import RecipeGenerator
|
|
||||||
|
|
||||||
templates_file = PROJECT_ROOT / 'recipe-generator' / 'recipe_templates.yaml'
|
|
||||||
|
|
||||||
return RecipeGenerator(templates_file)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def project_root():
|
|
||||||
"""Return project root directory."""
|
|
||||||
return PROJECT_ROOT
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def ingredients_dir(project_root):
|
|
||||||
"""Return ingredients directory."""
|
|
||||||
return project_root / 'ingredients'
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def recipes_dir(project_root):
|
|
||||||
"""Return recipes directory."""
|
|
||||||
return project_root / 'recipes'
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def ingredients(ingredients_dir):
|
|
||||||
"""List all .ks ingredient files."""
|
|
||||||
return list(ingredients_dir.glob('**/*.ks'))
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def expected_recipes_dir(project_root):
|
|
||||||
"""Return expected recipes directory for golden masters."""
|
|
||||||
return project_root / 'tests' / 'fixtures' / 'expected_recipes'
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
"""Integration tests for Phyllome OS recipe generator.
|
|
||||||
|
|
||||||
These tests verify the complete recipe generation workflow.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
from pathlib import Path
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
|
|
||||||
# Use actual project root
|
|
||||||
PROJECT_ROOT = Path('/home/lukas/Code/virt/phyllomeos')
|
|
||||||
RECIPE_GENERATOR_DIR = PROJECT_ROOT / 'recipe-generator'
|
|
||||||
RECIPE_DIR = PROJECT_ROOT / 'recipes'
|
|
||||||
INGREDIENTS_DIR = PROJECT_ROOT / 'ingredients'
|
|
||||||
CONTAINER_DIR = PROJECT_ROOT / 'tests' / 'container'
|
|
||||||
|
|
||||||
|
|
||||||
def test_generate_recipes_from_manifest():
|
|
||||||
"""Test generating all recipes from manifest."""
|
|
||||||
os.chdir(RECIPE_GENERATOR_DIR)
|
|
||||||
|
|
||||||
result = subprocess.run(
|
|
||||||
['python3', 'generate_recipe.py',
|
|
||||||
'--manifest', 'recipes_manifest.yaml',
|
|
||||||
'--output-dir', '../recipes/'],
|
|
||||||
capture_output=True,
|
|
||||||
text=True
|
|
||||||
)
|
|
||||||
|
|
||||||
assert result.returncode == 0, f"Recipe generation failed: {result.stderr}"
|
|
||||||
assert 'Generating:' in result.stdout
|
|
||||||
|
|
||||||
|
|
||||||
def test_validate_all_generated_recipes():
|
|
||||||
"""Test validating all generated recipes."""
|
|
||||||
# Count generated recipes
|
|
||||||
recipe_count = len(list(RECIPE_DIR.glob('*.cfg')))
|
|
||||||
assert recipe_count > 0, f"Expected recipes, got {recipe_count}"
|
|
||||||
|
|
||||||
# Validate each recipe
|
|
||||||
for recipe_file in RECIPE_DIR.glob('*.cfg'):
|
|
||||||
content = recipe_file.read_text()
|
|
||||||
assert len(content) > 0, f"Recipe {recipe_file.name} is empty"
|
|
||||||
assert '%include' in content, f"Recipe {recipe_file.name} missing %include"
|
|
||||||
|
|
||||||
|
|
||||||
def test_make_targets():
|
|
||||||
"""Test Makefile targets work."""
|
|
||||||
# Test generate-recipes
|
|
||||||
result = subprocess.run(
|
|
||||||
['make', 'generate-recipes'],
|
|
||||||
cwd=RECIPE_GENERATOR_DIR,
|
|
||||||
capture_output=True,
|
|
||||||
text=True
|
|
||||||
)
|
|
||||||
assert result.returncode == 0, f"make generate-recipes failed: {result.stderr}"
|
|
||||||
|
|
||||||
|
|
||||||
def test_container_build():
|
|
||||||
"""Test container builds successfully."""
|
|
||||||
result = subprocess.run(
|
|
||||||
['podman', 'build', '-t', 'phyllo/test-runner', '.'],
|
|
||||||
cwd=CONTAINER_DIR,
|
|
||||||
capture_output=True,
|
|
||||||
text=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# Should build even if podman fails (might not be installed)
|
|
||||||
# The important thing is the Containerfile syntax is valid
|
|
||||||
if result.returncode != 0 and 'command not found' not in result.stderr:
|
|
||||||
pytest.fail(f"Container build failed: {result.stderr}")
|
|
||||||
|
|
||||||
|
|
||||||
def test_ingredients_structure():
|
|
||||||
"""Verify ingredient directory structure."""
|
|
||||||
# Check core directories
|
|
||||||
assert (INGREDIENTS_DIR / 'core' / 'security').exists()
|
|
||||||
|
|
||||||
# Check desktop directories
|
|
||||||
assert (INGREDIENTS_DIR / 'desktop' / 'gnome').exists()
|
|
||||||
assert (INGREDIENTS_DIR / 'desktop' / 'labwc').exists()
|
|
||||||
# vmm is now in virtual-machine-manager directory (under packages)
|
|
||||||
# assert (INGREDIENTS_DIR / 'desktop' / 'vmm').exists()
|
|
||||||
|
|
||||||
# Check hypervisor directories
|
|
||||||
assert (INGREDIENTS_DIR / 'hypervisor' / 'base').exists()
|
|
||||||
assert (INGREDIENTS_DIR / 'hypervisor' / 'base').exists()
|
|
||||||
|
|
||||||
# Check live directories
|
|
||||||
assert (INGREDIENTS_DIR / 'live' / 'core' / 'bootloader').exists()
|
|
||||||
assert (INGREDIENTS_DIR / 'live' / 'post').exists()
|
|
||||||
|
|
||||||
# Count ingredients
|
|
||||||
ingredient_count = len(list(INGREDIENTS_DIR.glob('**/*.ks')))
|
|
||||||
assert ingredient_count >= 45, f"Expected at least 45 ingredients, found {ingredient_count}"
|
|
||||||
@@ -1,269 +0,0 @@
|
|||||||
"""Tests for the Recipe Generator."""
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
from pathlib import Path
|
|
||||||
import sys
|
|
||||||
|
|
||||||
RECIPE_GENERATOR_DIR = Path(__file__).parent.parent / 'recipe-generator'
|
|
||||||
sys.path.insert(0, str(RECIPE_GENERATOR_DIR))
|
|
||||||
|
|
||||||
from recipe_generator import RecipeGenerator
|
|
||||||
|
|
||||||
|
|
||||||
class TestRecipeGenerator:
|
|
||||||
"""Test RecipeGenerator class."""
|
|
||||||
|
|
||||||
def setup_method(self):
|
|
||||||
"""Set up test fixtures."""
|
|
||||||
project_root = Path(__file__).parent.parent
|
|
||||||
self.generator = RecipeGenerator(
|
|
||||||
project_root / 'recipe-generator' / 'recipe_templates.yaml'
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_template_loading(self):
|
|
||||||
"""Test that templates are loaded correctly."""
|
|
||||||
assert isinstance(self.generator.templates, dict)
|
|
||||||
assert len(self.generator.templates) == 2
|
|
||||||
assert 'install' in self.generator.templates
|
|
||||||
assert 'live' in self.generator.templates
|
|
||||||
|
|
||||||
def test_validate_template_success(self):
|
|
||||||
"""Test validation of valid templates."""
|
|
||||||
template = self.generator.templates['install']
|
|
||||||
errors = self.generator.validate_template(template)
|
|
||||||
assert errors == []
|
|
||||||
|
|
||||||
def test_validate_template_missing_key(self):
|
|
||||||
"""Test validation detects missing keys."""
|
|
||||||
template = {'base': 'core'}
|
|
||||||
errors = self.generator.validate_template(template)
|
|
||||||
assert any('Missing required key' in error for error in errors)
|
|
||||||
|
|
||||||
def test_validate_template_missing_ingredient(self):
|
|
||||||
"""Test validation detects missing ingredients."""
|
|
||||||
template = {
|
|
||||||
'description': 'Test',
|
|
||||||
'base': 'core',
|
|
||||||
'required': [
|
|
||||||
{'storage': 'core-storage'},
|
|
||||||
{'nonexistent': 'nonexistent-ingredient'}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
errors = self.generator.validate_template(template)
|
|
||||||
assert any('not found' in error for error in errors)
|
|
||||||
|
|
||||||
def test_generate_virtual_desktop_basic(self):
|
|
||||||
"""Test generating basic desktop recipe."""
|
|
||||||
content = self.generator.generate_recipe('install', '43',
|
|
||||||
desktop='gnome',
|
|
||||||
storage='standard',
|
|
||||||
security='secure')
|
|
||||||
assert '# An install recipe for desktop, server, or hypervisor' in content
|
|
||||||
assert '%include ingredients/core/base.ks' in content
|
|
||||||
assert '%include ingredients/desktop/gnome/packages.ks' in content
|
|
||||||
assert '%include ingredients/repo/fedora-43-mirrors.ks' in content
|
|
||||||
assert '%include ingredients/core/security/enabled.ks' in content
|
|
||||||
|
|
||||||
def test_generate_virtual_desktop_encrypted(self):
|
|
||||||
"""Test generating encrypted desktop recipe."""
|
|
||||||
content = self.generator.generate_recipe('install', 'rawhide',
|
|
||||||
desktop='gnome',
|
|
||||||
storage='encrypted',
|
|
||||||
security='secure')
|
|
||||||
assert '%include ingredients/storage/encrypted.ks' in content
|
|
||||||
|
|
||||||
def test_generate_virtual_desktop_labwc(self):
|
|
||||||
"""Test generating LabWC desktop recipe."""
|
|
||||||
content = self.generator.generate_recipe('install', '43',
|
|
||||||
desktop='labwc',
|
|
||||||
storage='standard',
|
|
||||||
security='secure')
|
|
||||||
assert '%include ingredients/desktop/labwc/config.ks' in content
|
|
||||||
assert '%include ingredients/desktop/gnome/packages.ks' not in content
|
|
||||||
|
|
||||||
def test_generate_virtual_desktop_devel(self):
|
|
||||||
"""Test generating development mode desktop recipe."""
|
|
||||||
content = self.generator.generate_recipe('install', '43',
|
|
||||||
desktop='gnome',
|
|
||||||
storage='standard',
|
|
||||||
security='off')
|
|
||||||
assert '%include ingredients/core/security/disabled.ks' in content
|
|
||||||
|
|
||||||
def test_generate_virtual_server(self):
|
|
||||||
"""Test generating server recipe."""
|
|
||||||
content = self.generator.generate_recipe('install', 'rawhide',
|
|
||||||
initial_setup='server',
|
|
||||||
security='secure')
|
|
||||||
assert '# An install recipe for desktop, server, or hypervisor' in content
|
|
||||||
assert '%include ingredients/initial-setup/server/config.ks' in content
|
|
||||||
|
|
||||||
def test_generate_desktop_hypervisor_amd(self):
|
|
||||||
"""Test generating AMD CPU hypervisor recipe."""
|
|
||||||
content = self.generator.generate_recipe('install', 'rawhide',
|
|
||||||
variant_type='hypervisor',
|
|
||||||
hypervisor='base',
|
|
||||||
hypervisor_type='amdcpu',
|
|
||||||
security='secure')
|
|
||||||
assert '%include ingredients/hypervisor/amdcpu.ks' in content
|
|
||||||
assert '%include ingredients/hypervisor/intelcpu.ks' not in content
|
|
||||||
|
|
||||||
def test_generate_desktop_hypervisor_intel_gpu(self):
|
|
||||||
"""Test generating Intel CPU+GPU hypervisor recipe."""
|
|
||||||
content = self.generator.generate_recipe('install', 'rawhide',
|
|
||||||
variant_type='hypervisor',
|
|
||||||
hypervisor='base',
|
|
||||||
hypervisor_type='intelcpu',
|
|
||||||
security='secure')
|
|
||||||
assert '%include ingredients/hypervisor/intelcpu.ks' in content
|
|
||||||
|
|
||||||
def test_generate_live_desktop(self):
|
|
||||||
"""Test generating live desktop recipe."""
|
|
||||||
content = self.generator.generate_recipe('live', 'rawhide',
|
|
||||||
desktop='gnome',
|
|
||||||
security='secure')
|
|
||||||
assert '# A live recipe for live-desktop or live-server' in content
|
|
||||||
assert '%include ingredients/live/core/base.ks' in content
|
|
||||||
assert '%include ingredients/live/core/storage.ks' in content
|
|
||||||
|
|
||||||
def test_generate_live_server(self):
|
|
||||||
"""Test generating live server recipe."""
|
|
||||||
content = self.generator.generate_recipe('live', 'rawhide',
|
|
||||||
security='secure')
|
|
||||||
assert '# A live recipe for live-desktop or live-server' in content
|
|
||||||
assert '%include ingredients/live/core/base.ks' in content
|
|
||||||
|
|
||||||
def test_no_duplicate_includes(self):
|
|
||||||
"""Test that duplicate includes are prevented."""
|
|
||||||
content = self.generator.generate_recipe('install', 'rawhide',
|
|
||||||
variant_type='hypervisor',
|
|
||||||
hypervisor='base',
|
|
||||||
hypervisor_type='intelcpu',
|
|
||||||
security='secure')
|
|
||||||
includes = [line for line in content.split('\n') if line.startswith('%include')]
|
|
||||||
paths = [line.split()[1] for line in includes]
|
|
||||||
assert len(paths) == len(set(paths)), "Found duplicate %include entries"
|
|
||||||
|
|
||||||
def test_missing_ingredient_detection(self):
|
|
||||||
"""Test that missing ingredients are detected."""
|
|
||||||
content = self.generator.generate_recipe('install', '43',
|
|
||||||
desktop='gnome',
|
|
||||||
storage='standard',
|
|
||||||
security='secure')
|
|
||||||
issues = self.generator.validate_recipe(content)
|
|
||||||
assert issues == [], f"Found missing ingredients: {issues}"
|
|
||||||
|
|
||||||
def test_filename_generation_standard(self):
|
|
||||||
"""Test filename generation for standard configuration."""
|
|
||||||
filename = self.generator.generate_filename('install', '43',
|
|
||||||
desktop='gnome',
|
|
||||||
storage='standard',
|
|
||||||
security='secure')
|
|
||||||
assert filename == 'install_43.cfg'
|
|
||||||
|
|
||||||
def test_filename_generation_encrypted(self):
|
|
||||||
"""Test filename generation for encrypted storage."""
|
|
||||||
filename = self.generator.generate_filename('install', 'rawhide',
|
|
||||||
desktop='gnome',
|
|
||||||
storage='encrypted',
|
|
||||||
security='secure')
|
|
||||||
assert filename == 'install_encrypted_rawhide.cfg'
|
|
||||||
|
|
||||||
def test_filename_generation_devel(self):
|
|
||||||
"""Test filename generation for development mode."""
|
|
||||||
filename = self.generator.generate_filename('install', '43',
|
|
||||||
desktop='gnome',
|
|
||||||
storage='standard',
|
|
||||||
security='off')
|
|
||||||
assert filename == 'install_devel_43.cfg'
|
|
||||||
|
|
||||||
def test_filename_generation_hypervisor(self):
|
|
||||||
"""Test filename generation for hypervisor."""
|
|
||||||
filename = self.generator.generate_filename('install', 'rawhide',
|
|
||||||
variant_type='hypervisor',
|
|
||||||
hypervisor='base',
|
|
||||||
hypervisor_type='intelcpu',
|
|
||||||
security='secure')
|
|
||||||
assert filename == 'install_hypervisor_intelcpu_rawhide.cfg'
|
|
||||||
|
|
||||||
def test_invalid_recipe_type(self):
|
|
||||||
"""Test error on invalid recipe type."""
|
|
||||||
with pytest.raises(SystemExit) as exc_info:
|
|
||||||
self.generator.generate_recipe('nonexistent-type', '43')
|
|
||||||
assert exc_info.value.code == 1
|
|
||||||
|
|
||||||
def test_manifest_validation_missing_recipes_key(self):
|
|
||||||
"""Test manifest validation detects missing recipes key."""
|
|
||||||
manifest = {}
|
|
||||||
errors = self.generator.validate_manifest(manifest)
|
|
||||||
assert any('recipes' in error for error in errors)
|
|
||||||
|
|
||||||
def test_manifest_validation_missing_name(self):
|
|
||||||
"""Test manifest validation detects missing recipe name."""
|
|
||||||
manifest = {'recipes': [{}]}
|
|
||||||
errors = self.generator.validate_manifest(manifest)
|
|
||||||
assert any('name' in error for error in errors)
|
|
||||||
|
|
||||||
def test_manifest_validation_missing_version(self):
|
|
||||||
"""Test manifest validation detects missing version."""
|
|
||||||
manifest = {'recipes': [{'name': 'test', 'variants': [{}]}]}
|
|
||||||
errors = self.generator.validate_manifest(manifest)
|
|
||||||
assert any('version' in error for error in errors)
|
|
||||||
|
|
||||||
def test_get_ksversion_43(self):
|
|
||||||
"""Test version mapping for Fedora 43."""
|
|
||||||
version = self.generator.get_ksversion('43')
|
|
||||||
assert version == 'F42'
|
|
||||||
|
|
||||||
def test_get_ksversion_rawhide(self):
|
|
||||||
"""Test version mapping for rawhide."""
|
|
||||||
version = self.generator.get_ksversion('rawhide')
|
|
||||||
assert version is None
|
|
||||||
|
|
||||||
def test_validate_recipe_semantic_f42(self):
|
|
||||||
"""Test semantic validation with valid recipe for F42."""
|
|
||||||
content = """text
|
|
||||||
poweroff
|
|
||||||
zerombr
|
|
||||||
clearpart --all --initlabel
|
|
||||||
part /boot/efi --fstype="efi" --size=512
|
|
||||||
part / --fstype="ext4" --grow
|
|
||||||
%packages
|
|
||||||
|
|
||||||
%end
|
|
||||||
"""
|
|
||||||
issues = self.generator.validate_recipe_semantic(content, '43')
|
|
||||||
assert issues == []
|
|
||||||
|
|
||||||
def test_validate_recipe_semantic_invalid_syntax(self):
|
|
||||||
"""Test semantic validation detects invalid syntax."""
|
|
||||||
content = "validcommand\ninvalidcommand without proper format\n%packages\n%end"
|
|
||||||
issues = self.generator.validate_recipe_semantic(content, '43')
|
|
||||||
assert len(issues) > 0
|
|
||||||
|
|
||||||
def test_validate_recipe_semantic_empty(self):
|
|
||||||
"""Test semantic validation with empty content."""
|
|
||||||
content = ""
|
|
||||||
issues = self.generator.validate_recipe_semantic(content, '43')
|
|
||||||
assert issues == []
|
|
||||||
|
|
||||||
def test_filename_generation_with_guest_agents(self):
|
|
||||||
"""Test filename includes 'virtual' when guest_agents=True."""
|
|
||||||
filename = self.generator.generate_filename('install', '43',
|
|
||||||
variant_type='desktop',
|
|
||||||
guest_agents=True)
|
|
||||||
assert filename == 'install_virtual_desktop_43.cfg'
|
|
||||||
|
|
||||||
def test_filename_generation_with_hardware_support(self):
|
|
||||||
"""Test filename includes 'hardware-support' when enabled."""
|
|
||||||
filename = self.generator.generate_filename('install', '43',
|
|
||||||
variant_type='desktop',
|
|
||||||
hardware_support=True)
|
|
||||||
assert filename == 'install_desktop_hardware-support_43.cfg'
|
|
||||||
|
|
||||||
def test_filename_generation_with_both_modifiers(self):
|
|
||||||
"""Test filename includes both modifiers when enabled."""
|
|
||||||
filename = self.generator.generate_filename('install', '43',
|
|
||||||
variant_type='desktop',
|
|
||||||
guest_agents=True,
|
|
||||||
hardware_support=True)
|
|
||||||
assert filename == 'install_virtual_desktop_hardware-support_43.cfg'
|
|
||||||
Reference in New Issue
Block a user