feat(template): check-win-iso (massgrave resolver) + patch-win-iso

Add `ci template check-win-iso`: parse the massgrave windows-server-links
markdown source on GitHub for the newest Windows Server 2025 build, file
name and link, and report whether it is already in <CI_ROOT>/iso/. The
download itself stays manual — the massgrave link is behind a Cloudflare
Turnstile file host, not scriptable.

Add `ci template patch-win-iso --in ISO [--out ISO]`: standalone equivalent
of deploy-win Step 4 — inject autounattend.xml + post-install.ps1 and a
no-prompt boot image into a manually downloaded ISO, producing a
ready-to-deploy `.patched.iso`.

winimage/massgrave.py does the parse (no auto-download). RUNBOOK §5
documents the check → download → patch → deploy workflow. Coverage 93.6%.
This commit is contained in:
2026-06-09 18:53:04 +02:00
parent c257c931c3
commit 3680f07ee3
6 changed files with 309 additions and 0 deletions
+35
View File
@@ -11,6 +11,41 @@ import pytest
from ci_orchestrator.winimage import autounattend as au
from ci_orchestrator.winimage import iso_patch as ip
from ci_orchestrator.winimage import massgrave as mg
# ── massgrave resolver ───────────────────────────────────────────────────────
_SAMPLE_MD = """\
## Windows Server 2025
Build - 26100.32860 (May 2026)
| English | x64 | [en-us_windows_server_2025_updated_may_2026_x64_dvd_abc.iso](https://zerofs.link/f/AAA/)|
| Italian | x64 | [it-it_windows_server_2025_updated_may_2026_x64_dvd_abc.iso](https://zerofs.link/f/BBB/)|
Build - 26100.1742
| English | x64 | [X23-81958_26100.1742_en-us.iso](https://oemsoc.download.prss.microsoft.com/x.iso?t=z)|
## Windows Server 2022
| English | x64 | [en-us_windows_server_2022.iso](https://zerofs.link/f/CCC/)|
"""
def test_resolve_ws2025_picks_newest_english() -> None:
i = mg.resolve_ws2025(_SAMPLE_MD, lang="English", arch="x64")
assert i.build == "26100.32860"
assert i.filename.startswith("en-us_windows_server_2025_updated")
assert i.url == "https://zerofs.link/f/AAA/"
def test_resolve_ws2025_italian() -> None:
assert mg.resolve_ws2025(_SAMPLE_MD, lang="Italian").url == "https://zerofs.link/f/BBB/"
def test_resolve_ws2025_not_found() -> None:
with pytest.raises(click.ClickException, match="No Windows Server 2025"):
mg.resolve_ws2025(_SAMPLE_MD, lang="Klingon")
def test_ws2025_section_missing() -> None:
with pytest.raises(click.ClickException, match="section not found"):
mg._ws2025_section("## Windows Server 2022\nnothing here")
# ── autounattend ───────────────────────────────────────────────────────────