From 167a22ad600daf94b1bef5ffb405ef5df3364214 Mon Sep 17 00:00:00 2001 From: Roger Chappel Date: Sun, 6 Sep 2026 23:03:26 +1000 Subject: [PATCH 1/3] test: verify Python interpreter resolution --- package.json | 3 ++- scripts/resolve-python.sh | 35 ++++++++++++++++++++++++++++++ scripts/test-resolve-python.sh | 39 ++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) create mode 100755 scripts/resolve-python.sh create mode 100755 scripts/test-resolve-python.sh diff --git a/package.json b/package.json index b11929a..80b90bb 100644 --- a/package.json +++ b/package.json @@ -15,10 +15,11 @@ "check": "tsc --noEmit", "package-manager:check": "node scripts/check-package-manager.mjs", "docs:check": "node scripts/check-docs.mjs", + "python:check": "bash scripts/test-resolve-python.sh", "start": "node dist/index.js", "check:templates": "pnpm build && node scripts/check-template-registry.mjs", "smoke:init": "bash scripts/smoke-init.sh", - "release:check": "pnpm run package-manager:check && pnpm run docs:check && pnpm run build && pnpm test && pnpm run smoke && pnpm run package:smoke", + "release:check": "pnpm run package-manager:check && pnpm run docs:check && pnpm run python:check && pnpm run build && pnpm test && pnpm run smoke && pnpm run package:smoke", "test": "pnpm run build && node scripts/check-template-registry.mjs", "smoke": "pnpm run smoke:init", "package:smoke": "pnpm run build && node scripts/package-smoke.mjs" diff --git a/scripts/resolve-python.sh b/scripts/resolve-python.sh new file mode 100755 index 0000000..d35d64c --- /dev/null +++ b/scripts/resolve-python.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +set -euo pipefail + +minimum="3.11" + +is_supported() { + "$1" -c 'import sys; raise SystemExit(0 if sys.version_info >= (3, 11) else 1)' >/dev/null 2>&1 +} + +if [ -n "${STACKFORGE_PYTHON:-}" ]; then + if ! command -v "$STACKFORGE_PYTHON" >/dev/null 2>&1; then + echo "StackForge: STACKFORGE_PYTHON '$STACKFORGE_PYTHON' was not found; set it to a Python >= $minimum interpreter." >&2 + exit 1 + fi + candidate="$(command -v "$STACKFORGE_PYTHON")" + if ! is_supported "$candidate"; then + echo "StackForge: STACKFORGE_PYTHON '$STACKFORGE_PYTHON' must be Python >= $minimum." >&2 + exit 1 + fi + printf '%s\n' "$candidate" + exit 0 +fi + +for name in python3.13 python3.12 python3.11 python3; do + if command -v "$name" >/dev/null 2>&1; then + candidate="$(command -v "$name")" + if is_supported "$candidate"; then + printf '%s\n' "$candidate" + exit 0 + fi + fi +done + +echo "StackForge: Python >= $minimum is required for the python-api smoke test. Install it or set STACKFORGE_PYTHON to a compatible interpreter." >&2 +exit 1 diff --git a/scripts/test-resolve-python.sh b/scripts/test-resolve-python.sh new file mode 100755 index 0000000..46eadeb --- /dev/null +++ b/scripts/test-resolve-python.sh @@ -0,0 +1,39 @@ +#!/bin/bash +set -euo pipefail + +repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +tmp_dir="$(mktemp -d)" +trap 'rm -rf "$tmp_dir"' EXIT + +make_python() { + name="$1" + supported="$2" + cat > "$tmp_dir/$name" < "$tmp_dir/out" 2> "$tmp_dir/err"; then + echo "incompatible configured Python unexpectedly succeeded" >&2 + exit 1 +fi +grep -q 'STACKFORGE_PYTHON.*Python >= 3.11' "$tmp_dir/err" + +# With no compatible candidate, resolution fails independently of the host Python. +rm -f "$tmp_dir/python3.12" +if PATH="$tmp_dir" /bin/bash "$repo_root/scripts/resolve-python.sh" > "$tmp_dir/out" 2> "$tmp_dir/err"; then + echo "missing compatible Python unexpectedly succeeded" >&2 + exit 1 +fi +grep -q 'Install it or set STACKFORGE_PYTHON' "$tmp_dir/err" + +echo "resolve-python tests ok" From 8dea7d707936d4a05ed0e37426349018d9096c44 Mon Sep 17 00:00:00 2001 From: Roger Chappel Date: Sun, 6 Sep 2026 23:03:26 +1000 Subject: [PATCH 2/3] fix: resolve compatible Python for smoke tests --- scripts/smoke-init.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/smoke-init.sh b/scripts/smoke-init.sh index 84cce9c..712abf7 100755 --- a/scripts/smoke-init.sh +++ b/scripts/smoke-init.sh @@ -181,7 +181,8 @@ grep -q 'name = "my-api"' 'My API/pyproject.toml' node "$repo_root/dist/index.js" init python-api '123 Weird.API!' > python-punctuated.json test -f '123 Weird.API!/src/_123_weird_api/main.py' grep -q 'name = "123-weird-api"' '123 Weird.API!/pyproject.toml' -python3 -m venv python-venv +python_interpreter="$("$repo_root/scripts/resolve-python.sh")" +"$python_interpreter" -m venv python-venv python-venv/bin/python -m pip install './My API' './123 Weird.API!' python-venv/bin/python -c 'from my_api.main import app; from _123_weird_api.main import app as numbered_app; assert app.title == "My API"; assert numbered_app.title == "123 Weird.API!"' node "$repo_root/dist/index.js" init next-app web-app > next.json From 841f3d5598cd1ec24d98e43b0dcb385142085e45 Mon Sep 17 00:00:00 2001 From: Roger Chappel Date: Sun, 6 Sep 2026 23:03:26 +1000 Subject: [PATCH 3/3] docs: document Python smoke prerequisite --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 7f0befe..11f8173 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,10 @@ packages. StackForge requires Node.js 20 or newer. Its build, template checks, and CLI smoke tests run in CI on both Node.js 20 and the primary Node.js 22 runtime. +The full contributor `pnpm run release:check` also requires Python 3.11 or +newer to install and import the generated `python-api` projects. StackForge +checks `python3.13`, `python3.12`, `python3.11`, then `python3`; set +`STACKFORGE_PYTHON` to select another compatible interpreter explicitly. ## Status