diff --git a/.ci/build-manifest.py b/.ci/build-manifest.py index 529bb92..16ca8b2 100644 --- a/.ci/build-manifest.py +++ b/.ci/build-manifest.py @@ -146,6 +146,29 @@ def parse_readme_sections(repo_root: str) -> dict: return out +def screenshot_captions(repo_root: str) -> dict: + """Numbered captions from the readme `== Screenshots ==` block (N -> caption).""" + for name, body in parse_readme_sections(repo_root).items(): + if section_key(name) == "screenshots": + caps = {} + for line in body.splitlines(): + m = re.match(r"^\s*(\d+)\.\s+(.*\S)", line) + if m: + caps[int(m.group(1))] = m.group(2).strip() + return caps + return {} + + +def build_screenshots(urls: dict, repo_root: str) -> dict: + """Pair release-provided screenshot URLs {N: src} with the readme's numbered + captions into the WP `screenshots` field ({N: {src, caption}}).""" + caps = screenshot_captions(repo_root) + return { + str(n): {"src": urls[str(n)], "caption": caps.get(n, "")} + for n in sorted(int(k) for k in urls) + } + + def build_sections(base: dict, repo_root: str, autogen: bool, strip_cfg) -> dict: resolved = {} # 1. curated overrides (.mu-manifest.yaml sections). @@ -168,6 +191,8 @@ def build_sections(base: dict, repo_root: str, autogen: bool, strip_cfg) -> dict # 2. readme.txt == Section == blocks (the WP-native default). for name, body in parse_readme_sections(repo_root).items(): key = section_key(name) + if key == "screenshots": + continue # not a text tab — handled as the `screenshots` gallery. if key not in resolved: resolved[key] = md_section(wporg_subheads(body), key, strip_cfg) # 3. changelog fallback -> CHANGELOG.md. @@ -203,6 +228,7 @@ def main() -> None: sys.exit(f"build-manifest: {BASE_FILE} must be a mapping") computed = json.load(open(args.computed, encoding="utf-8")) + shots = computed.pop("_screenshots", None) # {N: src} from release.sh (channel URLs) sections = build_sections(base, repo_root, autogen, strip_cfg) result = dict(computed) @@ -212,6 +238,8 @@ def main() -> None: result[k] = v if sections: result["sections"] = sections + if shots: + result["screenshots"] = build_screenshots(shots, repo_root) with open(args.out, "w", encoding="utf-8") as fh: json.dump(result, fh, indent=2, ensure_ascii=False) diff --git a/.ci/release.sh b/.ci/release.sh index fb4064c..41a0e2a 100644 --- a/.ci/release.sh +++ b/.ci/release.sh @@ -157,11 +157,21 @@ ICONS='{}' if [ -f icons/icon-256x256.png ]; then ICONS="$(printf '{"1x":"%s/icon-128x128.png","2x":"%s/icon-256x256.png"}' "${RAW}" "${RAW}")" fi -python3 - "$NAME" "$SLUG" "$VER" "$DL" "$HOST/${CHANNEL%/*}/$SLUG" "$REQ" "$TESTED" "$RPHP" "$NOW" "$ICONS" > computed.json <<'PY' +# screenshot images (screenshots/screenshot-N.ext) -> {N: filename}; build-manifest +# pairs these with the readme == Screenshots == captions into the `screenshots` field. +SHOTS='{}' +if [ -d screenshots ]; then + SHOTS="$(ls screenshots 2>/dev/null | python3 -c 'import sys,re,json;print(json.dumps({m.group(1):m.group(0) for m in (re.match(r"screenshot-(\d+)\.(?:png|jpe?g|gif|webp)$",f,re.I) for f in sys.stdin.read().split()) if m}))' || echo '{}')" +fi +python3 - "$NAME" "$SLUG" "$VER" "$DL" "$HOST/${CHANNEL%/*}/$SLUG" "$REQ" "$TESTED" "$RPHP" "$NOW" "$ICONS" "$SHOTS" "$RAW" > computed.json <<'PY' import json, sys k = ["name","slug","version","download_url","homepage","requires","tested","requires_php","last_updated"] d = dict(zip(k, sys.argv[1:10])) d["icons"] = json.loads(sys.argv[10]) +shots = json.loads(sys.argv[11]) +if shots: + raw = sys.argv[12] + d["_screenshots"] = {n: f"{raw}/{fn}" for n, fn in shots.items()} json.dump(d, sys.stdout) PY @@ -175,6 +185,7 @@ mkdir -p "_upd/${SLUG}" rm -f "_upd/${SLUG}"/*.zip cp "${ZIP}" "_upd/${SLUG}/" [ -d icons ] && cp icons/icon-128x128.png icons/icon-256x256.png "_upd/${SLUG}/" 2>/dev/null || true +[ -d screenshots ] && cp screenshots/screenshot-*.* "_upd/${SLUG}/" 2>/dev/null || true ( cd _upd git config user.email "ci@${SSH_HOST}"