From 9f3d35b72f7a1baee64bbcc877dde4edb647694e Mon Sep 17 00:00:00 2001 From: Kawa Date: Fri, 10 Apr 2026 15:41:05 +0200 Subject: [PATCH] docs(06): create phase plan for wiring icon into intunewin export Co-Authored-By: Claude Opus 4.6 (1M context) --- .../06-wire-icon-intunewin/06-01-PLAN.md | 170 ++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 .planning/phases/06-wire-icon-intunewin/06-01-PLAN.md diff --git a/.planning/phases/06-wire-icon-intunewin/06-01-PLAN.md b/.planning/phases/06-wire-icon-intunewin/06-01-PLAN.md new file mode 100644 index 0000000..5a65ce0 --- /dev/null +++ b/.planning/phases/06-wire-icon-intunewin/06-01-PLAN.md @@ -0,0 +1,170 @@ +--- +phase: 06-wire-icon-intunewin +plan: 01 +type: execute +wave: 1 +depends_on: [] +files_modified: + - imptune/api/packages.py + - tests/test_packages.py +autonomous: true +requirements: + - PKG-04 +must_haves: + truths: + - "Exported .intunewin includes icon.png in staging when printer has an uploaded icon" + - "Exported .intunewin succeeds without error when printer has no icon" + artifacts: + - path: "imptune/api/packages.py" + provides: "Icon lookup and copy into tmpdir staging" + contains: "Icon.get_or_none" + - path: "tests/test_packages.py" + provides: "Integration tests for icon-in-package and no-icon baseline" + contains: "test_intunewin_includes_icon" + key_links: + - from: "imptune/api/packages.py" + to: "imptune/db/models.py" + via: "Icon.get_or_none(Icon.printer == printer.id)" + pattern: "Icon\\.get_or_none" + - from: "imptune/api/packages.py" + to: "imptune/config.py" + via: "cfg.ICONS_DIR for icon source path" + pattern: "cfg\\.ICONS_DIR" +--- + + +Wire the uploaded PNG icon into the .intunewin export pipeline so that printers with an uploaded icon include it in the deployment package. + +Purpose: Closes the PKG-04 gap — icon upload exists (Phase 5) but the .intunewin builder never receives the icon file. This is the last unsatisfied v1 requirement. +Output: Modified packages.py with icon lookup + copy, two new integration tests in test_packages.py. + + + +@C:/Users/SebastienQUEROL/.claude/get-shit-done/workflows/execute-plan.md +@C:/Users/SebastienQUEROL/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md +@.planning/phases/06-wire-icon-intunewin/06-RESEARCH.md + + + + +From imptune/db/models.py: +```python +class Icon(BaseModel): + printer = ForeignKeyField(Printer, unique=True, backref="icons") + sha256 = CharField() + original_filename = CharField() + size_bytes = IntegerField() + uploaded_at = DateTimeField(default=datetime.utcnow) + + class Meta: + table_name = "icon" +``` + +From imptune/config.py: +```python +ICONS_DIR = str(Path(DATA_DIR) / "icons") +``` + +From imptune/api/packages.py (insertion point — line 146, after driver extraction, before build_intunewin): +```python +# Line 132: with tempfile.TemporaryDirectory(prefix="imptune_") as tmpdir: +# Lines 134-139: write install.ps1, uninstall.ps1, detect.ps1 +# Lines 142-145: extract driver ZIP into tmpdir/drivers/ +# >>> INSERT ICON COPY HERE <<< +# Line 148: output_path = os.path.join(tmpdir, "out.intunewin") +# Line 149: build_intunewin(tmpdir, "install.ps1", output_path) +``` + +From tests/test_packages.py (existing fixtures): +```python +@pytest.fixture +def setup_printer_with_driver(tmp_data_dir, driver_zip_bytes): + # Creates Driver + Printer records, writes driver ZIP to cfg.DRIVERS_DIR + # Returns (printer, driver) +``` + + + + + + + Task 1: Add icon-in-package tests and wire icon into packages.py + tests/test_packages.py, imptune/api/packages.py + + - test_intunewin_includes_icon: upload a 256x256 PNG icon for the printer, monkeypatch build_intunewin to capture staged file list, call GET /printers/{id}/packages/intunewin, assert "icon.png" is in staged files and response is 200 + - test_intunewin_without_icon_succeeds: no icon uploaded, monkeypatch build_intunewin, call GET /printers/{id}/packages/intunewin, assert response is 200 (no crash from missing icon) + + + RED phase — add two tests to TestIntunewinDownload class in tests/test_packages.py: + + 1. `test_intunewin_includes_icon(self, client, setup_printer_with_driver, tmp_data_dir, monkeypatch)`: + - Create a 256x256 RGBA PNG using `PIL.Image.new("RGBA", (256, 256), color="red")` + - POST it to `/printers/{printer.id}/icon` as multipart file upload + - Assert upload returns 200 + - Define `fake_build(source_dir, setup_file, output_path)` that captures `os.listdir(source_dir)` into a list and writes `b"FAKE"` to output_path + - Monkeypatch `imptune.api.packages.build_intunewin` with fake_build + - GET `/printers/{printer.id}/packages/intunewin` + - Assert status 200 and `"icon.png"` in captured staged files + + 2. `test_intunewin_without_icon_succeeds(self, client, setup_printer_with_driver, monkeypatch)`: + - Same fake_build monkeypatch (no icon upload) + - GET `/printers/{printer.id}/packages/intunewin` + - Assert status 200 + + Run tests — both MUST fail (icon.png not staged, and second test should actually pass since no icon code yet — if it passes, that is acceptable for the baseline). + + GREEN phase — modify imptune/api/packages.py: + + 1. Add `import shutil` at top + 2. Add `from imptune.db.models import Icon` to the existing models import (line 12 area — add Icon next to Printer) + 3. Inside `get_intunewin_package()`, after the driver ZIP extraction block (after line 145) and BEFORE `build_intunewin()` (line 149), insert: + + ```python + # Copy icon into staging if one exists for this printer + icon_record = Icon.get_or_none(Icon.printer == printer.id) + if icon_record is not None: + icon_src = os.path.join(cfg.ICONS_DIR, icon_record.sha256) + if os.path.isfile(icon_src): + shutil.copy2(icon_src, os.path.join(tmpdir, "icon.png")) + ``` + + This is 4 lines of production code. The icon is optional — missing DB record or missing file on disk both result in silent skip (no error, export proceeds without icon). + + Run tests again — both MUST pass. + + + python -m pytest tests/test_packages.py -x -q + + + - test_intunewin_includes_icon passes: icon.png present in staged files when icon uploaded + - test_intunewin_without_icon_succeeds passes: export works with no icon + - All pre-existing test_packages.py tests still pass (no regressions) + - Full test suite green: python -m pytest tests/ -q + + + + + + +- `python -m pytest tests/test_packages.py -x -q` — all tests pass including two new icon tests +- `python -m pytest tests/ -q` — full suite green, no regressions +- Manual code review: `shutil.copy2` call is BEFORE `build_intunewin()` call (not after) +- Manual code review: `Icon` import added, `cfg.ICONS_DIR` used (not hardcoded path) + + + +1. Printers with an uploaded icon have icon.png included in .intunewin staging directory +2. Printers without an icon export successfully with no error +3. All existing tests pass without modification +4. PKG-04 requirement satisfied + + + +After completion, create `.planning/phases/06-wire-icon-intunewin/06-01-SUMMARY.md` +