Build the Windows installer in CI

The fourth leg of build-and-test.yml, in the shape of the Android one:
an image workflow that builds docker/windows and pushes it tagged by
the directory's tree id, and a job inside that image that lints the
Windows target — the only place the cfg(windows) branches are ever
compiled by CI — builds, runs the smoke tests docs/windows.md §6
specifies, packages, installs and uninstalls under Wine, and uploads
the installer. Every step was run by hand in the same container first.

The spec's open list closes with this: the four §3.2 items, the
licence page, and the leg. What remains is what Wine cannot show, and
§10 now lists it as the first real Windows run's checklist.
This commit is contained in:
2026-09-12 07:34:10 +02:00
parent 6609aa9acf
commit 43f70c4765
5 changed files with 336 additions and 37 deletions
+106
View File
@@ -365,6 +365,112 @@ jobs:
path: target-android/apk/darkroom.apk
if-no-files-found: error
windows-image:
uses: ./.gitea/workflows/windows-image.yml
# TRACES: FR-PLAT-WIN-3
# The Windows executable and its installer, cross-built from Linux
# (docs/windows.md §7). No Windows machine anywhere in this job: what it
# can prove is that the binary links, is a Windows executable with no
# MinGW runtime imports, starts under Wine, and that the installer installs
# and uninstalls under Wine. What it cannot prove — a Vulkan device, a
# render, the secret store — is a release step on a real machine (§6).
windows:
runs-on: linux/amd64
name: Windows (x86_64, cross)
needs: windows-image
container:
image: gitea.tourolle.paris/dtourolle/darkroom-windows:latest
env:
CARGO_INCREMENTAL: 0
CARGO_PROFILE_DEV_DEBUG: 0
CARGO_TARGET_DIR: target-windows
# Wine keeps its prefix under $HOME, which the image points at a
# directory that does not exist in a fresh container.
HOME: /tmp/home
steps:
- name: Checkout
uses: actions/checkout@v4
# Same step as the desktop leg: the models are LFS objects and the
# packager refuses pointers.
- name: Fetch the models
env:
LFS_TOKEN: ${{ secrets.GITEA_TOKEN || github.token }}
run: |
set -e
git lfs install --local
git config --local --get-regexp '^http\..*extraheader$' \
| cut -d' ' -f1 | sort -u \
| while read -r key; do git config --local --unset-all "$key"; done || true
git config --local lfs.url \
"https://x-access-token:${LFS_TOKEN}@gitea.tourolle.paris/dtourolle/DarkRoom.git/info/lfs"
git lfs pull
ls -l models/face models/scene
- name: Cache cargo
uses: actions/cache@v4
with:
path: |
/opt/cargo/registry
target-windows
key: windows-${{ hashFiles('**/Cargo.lock') }}
# The cfg(windows) branches are linted here and nowhere else: the
# desktop leg's clippy never compiles them.
- name: Clippy for the target
run: cargo clippy --release --target x86_64-pc-windows-gnu -p darkroom-desktop -- -D warnings
- name: Build
run: cargo build --release --target x86_64-pc-windows-gnu -p darkroom-desktop
- name: Smoke-test the executable
run: |
set -e
mkdir -p "$HOME"
EXE=target-windows/x86_64-pc-windows-gnu/release/darkroom-desktop.exe
file "$EXE"
file "$EXE" | grep -q 'PE32+' || { echo "FAIL: not a PE32+ executable"; exit 1; }
file "$EXE" | grep -q '(GUI)' || { echo "FAIL: not a GUI-subsystem executable"; exit 1; }
if x86_64-w64-mingw32-objdump -p "$EXE" | grep -iE 'libwinpthread|libgcc|libstdc'; then
echo "FAIL: the executable imports a MinGW runtime DLL"
exit 1
fi
x86_64-w64-mingw32-objdump -p "$EXE" | grep 'DLL Name' | sort -u
wineboot --init >/dev/null 2>&1 || true
OUT=$(wine "$EXE" --version 2>/dev/null)
echo "wine: $OUT"
echo "$OUT" | grep -q '^darkroom-desktop ' || { echo "FAIL: --version did not answer under Wine"; exit 1; }
- name: Package the installer
run: bash docker/windows/package.sh
- name: Smoke-test the installer
run: |
set -e
SETUP=$(ls target-windows/installer/DarkRoom-*-x86_64-setup.exe)
file "$SETUP" | grep -q 'PE32+' || { echo "FAIL: the installer is not 64-bit"; exit 1; }
wine "$SETUP" /S 2>/dev/null
INST=$(echo "$HOME"/.wine/drive_c/users/*/AppData/Local/Programs/DarkRoom)
ls "$INST"
[ "$(ls "$INST/models" | wc -l)" = 7 ] || { echo "FAIL: expected 7 model files"; exit 1; }
wine reg query 'HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall\DarkRoom' 2>/dev/null \
| grep -q DisplayVersion || { echo "FAIL: no uninstall registry key"; exit 1; }
wine "$INST/darkroom.exe" --version 2>/dev/null | grep -q '^darkroom-desktop ' \
|| { echo "FAIL: the installed executable does not run"; exit 1; }
wine "$INST/uninstall.exe" /S 2>/dev/null
sleep 3
[ ! -e "$INST" ] || { echo "FAIL: uninstall left $INST behind"; ls -R "$INST"; exit 1; }
echo "OK: installed and uninstalled under Wine"
- name: Upload the installer
uses: actions/upload-artifact@v3
with:
name: darkroom-windows-x86_64-setup
path: target-windows/installer/DarkRoom-*-x86_64-setup.exe
if-no-files-found: error
layering:
runs-on: linux/amd64
name: Layer separation