feat: add PyInstaller standalone binary builds #5
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build and Release Binaries | |
| on: | |
| release: | |
| types: [published] | |
| pull_request: | |
| branches: [master] | |
| paths: | |
| - 'src/**' | |
| - 'ha-mcp.spec' | |
| - 'mcpb/**' | |
| - '.github/workflows/build-binary.yml' | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Version to build (e.g., 4.7.4)' | |
| required: true | |
| default: '0.0.0-dev' | |
| # Restrict permissions by default (security best practice) | |
| permissions: | |
| contents: read | |
| jobs: | |
| build: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: ubuntu-latest | |
| artifact_name: ha-mcp-linux | |
| binary_ext: '' | |
| platform: linux | |
| create_mcpb: false | |
| - os: windows-latest | |
| artifact_name: ha-mcp-windows | |
| binary_ext: '.exe' | |
| platform: win32 | |
| create_mcpb: true | |
| - os: macos-latest | |
| artifact_name: ha-mcp-macos-arm64 | |
| binary_ext: '' | |
| platform: darwin | |
| create_mcpb: true | |
| runs-on: ${{ matrix.os }} | |
| name: Build on ${{ matrix.os }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.13' | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v4 | |
| with: | |
| version: "latest" | |
| - name: Create virtual environment and install dependencies | |
| run: | | |
| uv venv .venv | |
| uv pip install -e . pyinstaller | |
| shell: bash | |
| - name: Activate venv (Unix) | |
| if: runner.os != 'Windows' | |
| run: echo "$PWD/.venv/bin" >> $GITHUB_PATH | |
| - name: Activate venv (Windows) | |
| if: runner.os == 'Windows' | |
| run: echo "$PWD/.venv/Scripts" >> $env:GITHUB_PATH | |
| shell: pwsh | |
| - name: Build binary | |
| run: pyinstaller ha-mcp.spec | |
| - name: Test binary starts correctly (Unix) | |
| if: runner.os != 'Windows' | |
| run: | | |
| chmod +x dist/ha-mcp | |
| # Test that the binary starts and shows the FastMCP banner | |
| # Set dummy env vars so it doesn't fail on missing config | |
| export HOMEASSISTANT_URL=http://test:8123 | |
| export HOMEASSISTANT_TOKEN=test | |
| # Run binary in background, wait, then kill it | |
| ./dist/ha-mcp > output.txt 2>&1 & | |
| PID=$! | |
| sleep 5 | |
| kill $PID 2>/dev/null || true | |
| # Verify FastMCP banner appears (indicates successful startup) | |
| cat output.txt | |
| grep -q "FastMCP" output.txt | |
| echo "Binary started successfully!" | |
| - name: Test binary starts correctly (Windows) | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| $env:HOMEASSISTANT_URL = "http://test:8123" | |
| $env:HOMEASSISTANT_TOKEN = "test" | |
| # Start process and capture output | |
| $process = Start-Process -FilePath "dist\ha-mcp.exe" -NoNewWindow -PassThru -RedirectStandardOutput "output.txt" -RedirectStandardError "error.txt" | |
| Start-Sleep -Seconds 5 | |
| Stop-Process -Id $process.Id -Force -ErrorAction SilentlyContinue | |
| # Check output | |
| $output = Get-Content -Path "output.txt", "error.txt" -Raw -ErrorAction SilentlyContinue | |
| Write-Host $output | |
| if ($output -match "FastMCP") { | |
| Write-Host "Binary started successfully!" | |
| } else { | |
| Write-Host "Binary failed to start properly" | |
| exit 1 | |
| } | |
| - name: Set version | |
| id: version | |
| shell: bash | |
| run: | | |
| if [ "${{ github.event_name }}" = "release" ]; then | |
| VERSION="${{ github.event.release.tag_name }}" | |
| # Remove 'v' prefix if present | |
| VERSION="${VERSION#v}" | |
| else | |
| VERSION="${{ github.event.inputs.version }}" | |
| fi | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| - name: Rename binary for artifact | |
| shell: bash | |
| run: | | |
| mv dist/ha-mcp${{ matrix.binary_ext }} dist/${{ matrix.artifact_name }}${{ matrix.binary_ext }} | |
| - name: Create mcpb bundle (Windows/macOS only) | |
| if: matrix.create_mcpb | |
| shell: bash | |
| run: | | |
| VERSION="${{ steps.version.outputs.version }}" | |
| PLATFORM="${{ matrix.platform }}" | |
| BINARY_EXT="${{ matrix.binary_ext }}" | |
| # Create mcpb directory structure | |
| mkdir -p mcpb-bundle | |
| # Copy binary to bundle | |
| cp dist/${{ matrix.artifact_name }}${{ matrix.binary_ext }} mcpb-bundle/ha-mcp${{ matrix.binary_ext }} | |
| # Generate manifest.json from template | |
| sed -e "s/\${VERSION}/$VERSION/g" \ | |
| -e "s/\${PLATFORM}/$PLATFORM/g" \ | |
| -e "s/\${BINARY_EXT}/$BINARY_EXT/g" \ | |
| -e 's/\${__dirname}/\${__dirname}/g' \ | |
| mcpb/manifest.template.json > mcpb-bundle/manifest.json | |
| # Create .mcpb file (zip archive) | |
| cd mcpb-bundle | |
| if [ "${{ runner.os }}" = "Windows" ]; then | |
| 7z a -tzip "../${{ matrix.artifact_name }}.mcpb" * | |
| else | |
| zip -r "../${{ matrix.artifact_name }}.mcpb" * | |
| fi | |
| cd .. | |
| - name: Upload binary artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.artifact_name }} | |
| path: dist/${{ matrix.artifact_name }}${{ matrix.binary_ext }} | |
| if-no-files-found: error | |
| - name: Upload mcpb artifact | |
| if: matrix.create_mcpb | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.artifact_name }}-mcpb | |
| path: ${{ matrix.artifact_name }}.mcpb | |
| if-no-files-found: error | |
| release: | |
| needs: build | |
| runs-on: ubuntu-latest | |
| if: github.event_name == 'release' | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: artifacts | |
| - name: List artifacts | |
| run: find artifacts -type f | |
| - name: Upload binaries to release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| files: | | |
| artifacts/ha-mcp-linux/ha-mcp-linux | |
| artifacts/ha-mcp-windows/ha-mcp-windows.exe | |
| artifacts/ha-mcp-macos-arm64/ha-mcp-macos-arm64 | |
| artifacts/ha-mcp-windows-mcpb/ha-mcp-windows.mcpb | |
| artifacts/ha-mcp-macos-arm64-mcpb/ha-mcp-macos-arm64.mcpb |