Skip to content

fix: tighten wake word handling and add leak diagnostics #29

fix: tighten wake word handling and add leak diagnostics

fix: tighten wake word handling and add leak diagnostics #29

name: Build Multi-Platform
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
workflow_dispatch:
permissions:
contents: write
jobs:
detect-release:
name: Detect Release Version Change
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
outputs:
should_release: ${{ steps.detect.outputs.should_release }}
version: ${{ steps.detect.outputs.version }}
tag_name: ${{ steps.detect.outputs.tag_name }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Detect version change
id: detect
run: |
python - <<'PY'
import os
import pathlib
import subprocess
import tomllib
def set_output(name: str, value: str) -> None:
with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as fh:
fh.write(f"{name}={value}\n")
before = os.environ.get("GITHUB_EVENT_BEFORE", "")
current = tomllib.loads(pathlib.Path("pyproject.toml").read_text(encoding="utf-8"))["project"]["version"]
previous = None
if before and before != "0000000000000000000000000000000000000000":
try:
previous_text = subprocess.check_output(
["git", "show", f"{before}:pyproject.toml"],
text=True,
stderr=subprocess.DEVNULL,
)
previous = tomllib.loads(previous_text)["project"]["version"]
except Exception:
previous = None
should_release = previous != current
tag_name = f"v{current}"
print(f"previous={previous}")
print(f"current={current}")
print(f"should_release={str(should_release).lower()}")
set_output("should_release", str(should_release).lower())
set_output("version", current)
set_output("tag_name", tag_name)
PY
env:
GITHUB_EVENT_BEFORE: ${{ github.event.before }}
build-windows:
name: Build Windows EXE & Installer
runs-on: windows-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: '3.12'
cache: 'pip'
cache-dependency-path: |
requirements-windows.txt
pyproject.toml
- name: Validate version consistency
run: |
$code = @'
import pathlib
import re
import sys
import tomllib
py = tomllib.loads(pathlib.Path("pyproject.toml").read_text(encoding="utf-8"))
v1 = py["project"]["version"]
txt = pathlib.Path("src/__init__.py").read_text(encoding="utf-8")
m = re.search(r"__version__\s*=\s*\"([^\"]+)\"", txt)
v2 = m.group(1) if m else None
print(f"pyproject={v1}, src={v2}")
sys.exit(0 if (v1 and v1 == v2) else 1)
'@
python -c $code
shell: pwsh
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install "numpy>=1.24.0,<2.0.0" --only-binary=:all:
pip install -r requirements-windows.txt --verbose
shell: pwsh
- name: Build Single-File EXE
run: |
New-Item -ItemType Directory -Force -Path build-logs | Out-Null
python setup.py --build *>&1 | Tee-Object -FilePath build-logs/pyinstaller-single.log
if ($LASTEXITCODE -ne 0) {
Write-Error "PyInstaller single-file build failed"
exit $LASTEXITCODE
}
shell: pwsh
- name: Build Directory Mode for Installer
run: |
python setup.py --build-dir *>&1 | Tee-Object -FilePath build-logs/pyinstaller-dir.log
if ($LASTEXITCODE -ne 0) {
Write-Error "PyInstaller directory build failed"
exit $LASTEXITCODE
}
shell: pwsh
- name: Install NSIS
run: |
winget install --id NSIS.NSIS --exact --accept-source-agreements --accept-package-agreements -e --silent
Start-Sleep -Seconds 10
shell: pwsh
- name: Build NSIS Installer
run: |
$nsisPaths = @(
"C:\Program Files (x86)\NSIS\makensis.exe",
"C:\Program Files\NSIS\makensis.exe",
"C:\NSIS\makensis.exe"
)
$makensis = $null
foreach ($path in $nsisPaths) {
if (Test-Path $path) {
$makensis = $path
break
}
}
if (-not $makensis) {
Write-Error "NSIS makensis.exe not found"
exit 1
}
& $makensis "installer\installer.nsi" *>&1 | Tee-Object -FilePath build-logs/nsis.log
if ($LASTEXITCODE -ne 0) {
Write-Error "Installer build failed!"
exit 1
}
shell: pwsh
- name: Upload Windows build logs on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: windows-build-logs
path: |
build-logs/**
build/**
retention-days: 14
if-no-files-found: warn
- name: Upload Windows EXE
uses: actions/upload-artifact@v4
with:
name: ha-assistant-windows-exe
path: dist/HomeAssistantWindows.exe
retention-days: 30
- name: Upload Windows Installer
uses: actions/upload-artifact@v4
with:
name: ha-assistant-windows-installer
path: dist/HomeAssistantWindows_Setup.exe
retention-days: 30
build-macos:
name: Build macOS App
runs-on: macos-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: '3.12'
cache: 'pip'
cache-dependency-path: |
requirements-macos.txt
pyproject.toml
- name: Validate version consistency
run: |
python - <<'PY'
import pathlib
import re
import sys
import tomllib
py = tomllib.loads(pathlib.Path('pyproject.toml').read_text(encoding='utf-8'))
v1 = py['project']['version']
txt = pathlib.Path('src/__init__.py').read_text(encoding='utf-8')
m = re.search(r'__version__\s*=\s*"([^"]+)"', txt)
v2 = m.group(1) if m else None
print(f'pyproject={v1}, src={v2}')
raise SystemExit(0 if (v1 and v1 == v2) else 1)
PY
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements-macos.txt
- name: Build macOS App
run: |
mkdir -p build-logs
set -o pipefail
python setup.py --build 2>&1 | tee build-logs/pyinstaller-macos.log
- name: Create DMG
run: |
set -o pipefail
hdiutil create -volname "Home Assistant" -srcfolder dist/HomeAssistant.app -ov -format UDZO dist/HomeAssistant-macOS.dmg 2>&1 | tee build-logs/dmg.log
- name: Upload macOS build logs on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: macos-build-logs
path: |
build-logs/**
build/**
retention-days: 14
if-no-files-found: warn
- name: Upload macOS DMG
uses: actions/upload-artifact@v4
with:
name: ha-assistant-macos
path: dist/HomeAssistant-macOS.dmg
retention-days: 30
release:
name: Create Release
needs: [detect-release, build-windows, build-macos]
if: needs.detect-release.outputs.should_release == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download Windows EXE
uses: actions/download-artifact@v4
with:
name: ha-assistant-windows-exe
path: dist/
- name: Download Windows Installer
uses: actions/download-artifact@v4
with:
name: ha-assistant-windows-installer
path: dist/
- name: Download macOS DMG
uses: actions/download-artifact@v4
with:
name: ha-assistant-macos
path: dist/
- name: Generate latest.json
run: |
version="${{ needs.detect-release.outputs.version }}"
echo "{\"version\": \"$version\"}" > dist/latest.json
shell: bash
- name: Create Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.detect-release.outputs.tag_name }}
target_commitish: ${{ github.sha }}
name: ${{ needs.detect-release.outputs.tag_name }}
files: |
dist/HomeAssistantWindows.exe
dist/HomeAssistantWindows_Setup.exe
dist/HomeAssistant-macOS.dmg
dist/latest.json
draft: false
prerelease: false
generate_release_notes: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}