docs: expand CI/CD guide with NSIS launch function, VBS fallback, and local build testing

- Replace MUI_FINISHPAGE_RUN_PARAMETERS with RUN_FUNCTION (fixes quoting)
- Add embedded Python fallback to VBS hidden launcher
- Add .onInit file-lock detection for running instances
- Add section 11: local Windows build testing with NSIS
- Expand troubleshooting table with common build/install issues
This commit is contained in:
2026-03-24 12:46:38 +03:00
parent e32cf5fe58
commit 294c50a2eb

View File

@@ -342,12 +342,36 @@ InstallDir "$LOCALAPPDATA\${APPNAME}"
RequestExecutionLevel user RequestExecutionLevel user
; Optional: launch app after install (checkbox on finish page) ; Optional: launch app after install (checkbox on finish page)
; Direct bat approach (shows brief console flash): ; IMPORTANT: Do NOT use MUI_FINISHPAGE_RUN with MUI_FINISHPAGE_RUN_PARAMETERS —
; !define MUI_FINISHPAGE_RUN "$INSTDIR\MyApp.bat" ; NSIS Exec command chokes on the quoting. Use MUI_FINISHPAGE_RUN_FUNCTION instead:
; Preferred: VBS hidden launcher (no console window at all): !define MUI_FINISHPAGE_RUN ""
!define MUI_FINISHPAGE_RUN "wscript.exe"
!define MUI_FINISHPAGE_RUN_PARAMETERS '"$INSTDIR\scripts\start-hidden.vbs"'
!define MUI_FINISHPAGE_RUN_TEXT "Launch ${APPNAME}" !define MUI_FINISHPAGE_RUN_TEXT "Launch ${APPNAME}"
!define MUI_FINISHPAGE_RUN_FUNCTION LaunchApp
Function LaunchApp
ExecShell "open" "wscript.exe" '"$INSTDIR\scripts\start-hidden.vbs"'
Sleep 2000
ExecShell "open" "http://localhost:8765/" ; Open Web UI after server starts
FunctionEnd
; Detect running instance before install (file lock check)
Function .onInit
IfFileExists "$INSTDIR\python\python.exe" 0 done
ClearErrors
FileOpen $0 "$INSTDIR\python\python.exe" a
IfErrors locked
FileClose $0
Goto done
locked:
MessageBox MB_YESNOCANCEL|MB_ICONEXCLAMATION \
"${APPNAME} is currently running.$\n$\nYes = Stop and continue$\nNo = Continue anyway (may cause errors)$\nCancel = Abort" \
IDYES kill IDNO done
Abort
kill:
nsExec::ExecToLog 'wmic process where "ExecutablePath like $\'%AppName%python%$\'" call terminate'
Sleep 2000
done:
FunctionEnd
; Sections ; Sections
Section "!Core (required)" SecCore ; App files + uninstaller Section "!Core (required)" SecCore ; App files + uninstaller
@@ -365,17 +389,27 @@ Bat files briefly flash a console window even with `@echo off`. To avoid this,
use a VBS wrapper that all shortcuts and the finish page point to: use a VBS wrapper that all shortcuts and the finish page point to:
```vbs ```vbs
Set fso = CreateObject("Scripting.FileSystemObject")
Set WshShell = CreateObject("WScript.Shell") Set WshShell = CreateObject("WScript.Shell")
scriptDir = CreateObject("Scripting.FileSystemObject").GetParentFolderName(WScript.ScriptFullName) scriptDir = fso.GetParentFolderName(WScript.ScriptFullName)
appRoot = CreateObject("Scripting.FileSystemObject").GetParentFolderName(scriptDir) appRoot = fso.GetParentFolderName(scriptDir)
WshShell.CurrentDirectory = appRoot WshShell.CurrentDirectory = appRoot
' Run bat completely hidden (0 = hidden, False = don't wait) ' Use embedded Python if present (installed dist), otherwise system Python
WshShell.Run """" & appRoot & "\MyApp.bat""", 0, False embeddedPython = appRoot & "\python\python.exe"
If fso.FileExists(embeddedPython) Then
WshShell.Run """" & embeddedPython & """ -m your_package.main", 0, False
Else
WshShell.Run "python -m your_package.main", 0, False
End If
``` ```
Place in `scripts/start-hidden.vbs` and bundle it in the build script. Place in `scripts/start-hidden.vbs` and bundle it in the build script.
All NSIS shortcuts use: `"wscript.exe" '"$INSTDIR\scripts\start-hidden.vbs"'` All NSIS shortcuts use: `"wscript.exe" '"$INSTDIR\scripts\start-hidden.vbs"'`
**Important:** The embedded Python fallback is critical — the installed distribution
doesn't have Python on PATH, so `python` alone won't work. The dev environment uses
system Python, so the fallback handles both cases.
**CI dependencies:** `sudo apt-get install -y nsis msitools zip` **CI dependencies:** `sudo apt-get install -y nsis msitools zip`
Build: `makensis -DVERSION="${VERSION}" installer.nsi` Build: `makensis -DVERSION="${VERSION}" installer.nsi`
@@ -486,7 +520,64 @@ git push origin v0.2.0-alpha.1
- [ ] Configure `pyproject.toml` with `[tool.ruff]` and `[tool.pytest]` - [ ] Configure `pyproject.toml` with `[tool.ruff]` and `[tool.pytest]`
- [ ] Set up `.pre-commit-config.yaml` with ruff + black - [ ] Set up `.pre-commit-config.yaml` with ruff + black
## 11. Troubleshooting ## 11. Local Build Testing (Windows)
The CI builds on Linux, but you can build locally on Windows for faster iteration.
### 11.1. Prerequisites
Install NSIS (for installer builds):
```powershell
# If winget is not on PATH, use the full path:
& "$env:LOCALAPPDATA\Microsoft\WindowsApps\winget.exe" install NSIS.NSIS
# Installs to: C:\Program Files (x86)\NSIS\makensis.exe
```
### 11.2. Build Steps
```bash
# 1. Build frontend
npm ci && npm run build
# 2. Build Windows distribution (from Git Bash)
bash build-dist-windows.sh v1.0.0
# 3. Build NSIS installer
"/c/Program Files (x86)/NSIS/makensis.exe" -DVERSION="1.0.0" installer.nsi
# Output: build/MediaServer-v1.0.0-setup.exe
```
### 11.3. Common Issues
| Issue | Cause | Fix |
|-------|-------|-----|
| `zip: command not found` | Git Bash doesn't include `zip` | Harmless — only affects the portable ZIP, not the installer. Install `zip` via MSYS2 if needed |
| `Exec expects 1 parameters, got 2` | `MUI_FINISHPAGE_RUN_PARAMETERS` quoting breaks NSIS `Exec` | Use `MUI_FINISHPAGE_RUN_FUNCTION` instead (see section 6) |
| `Error opening file for writing: ...python\\_asyncio.pyd` | Server is running and has DLLs locked | Stop the server before installing. Add `.onInit` file-lock check (see section 6) |
| App doesn't start after install (Launch checkbox) | VBS uses `python` but embedded Python isn't on PATH | Use embedded Python fallback in VBS (see Hidden Launcher section) |
| `winget` not recognized | `winget.exe` exists but isn't on shell PATH | Use full path: `$env:LOCALAPPDATA\Microsoft\WindowsApps\winget.exe` |
| NSIS warning: `install function not referenced` | `MUI_FINISHPAGE_RUN` define is missing | `MUI_FINISHPAGE_RUN_FUNCTION` still requires `MUI_FINISHPAGE_RUN` to be defined (controls checkbox visibility). Set it to `""` |
| `dist/` has stale files after code changes | `build-dist-windows.sh` copies from source at build time | Re-run the full build script, or manually copy changed files into `dist/` |
### 11.4. Iterating on Installer Only
If you only changed `installer.nsi` (not app code), skip the full rebuild:
```bash
# Just rebuild the installer using existing dist/
"/c/Program Files (x86)/NSIS/makensis.exe" -DVERSION="1.0.0" installer.nsi
```
If you changed app code or dependencies, you must re-run `build-dist-windows.sh` first —
the `dist/` directory is a snapshot and won't pick up source changes automatically.
## 12. Troubleshooting
### Running server blocks installation
See section 11.3. The `.onInit` function in section 6 shows how to detect a locked
`python.exe` and prompt the user before proceeding.
### Release already exists for tag ### Release already exists for tag