ci: use Windows PowerShell, add preflight job, harden for self-hosted

- The runner has Windows PowerShell 5.1, not pwsh/PowerShell 7 — switch all
  steps from `shell: pwsh` to `shell: powershell`.
- Make the scripts 5.1-safe: force TLS 1.2 for HTTPS, -UseBasicParsing on
  Invoke-WebRequest, and write GITHUB_ENV as ascii (no BOM).
- Add a fast `preflight` job that validates the runner (OS, PowerShell, Python
  availability) in seconds; build-windows now `needs: [preflight]`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-17 20:33:54 -07:00
parent 9f06b45322
commit d82ee25916
+32 -11
View File
@@ -4,10 +4,12 @@ name: Build Windows
# Produces dist/macropad.exe as a build artifact, and on a version tag (v*) # Produces dist/macropad.exe as a build artifact, and on a version tag (v*)
# creates/updates a Gitea release and attaches the exe. # creates/updates a Gitea release and attaches the exe.
# #
# Note: actions/setup-python is intentionally NOT used — its Windows # Notes for self-hosted Windows runners:
# tool-cache install script hangs on self-hosted runners. Instead we use an # - Uses `shell: powershell` (Windows PowerShell 5.1); `pwsh`/PowerShell 7 is
# existing Python 3.11 if the VM has one, otherwise silently install it # not assumed to be installed.
# per-user (no elevation, no prompts). # - actions/setup-python is avoided (its Windows tool-cache install hangs on
# self-hosted runners); Python 3.11 is used if present, else silently
# installed per-user.
on: on:
workflow_dispatch: workflow_dispatch:
@@ -16,7 +18,22 @@ on:
- 'v*' - 'v*'
jobs: jobs:
# Fast smoke test so a broken runner fails in seconds, not minutes.
preflight:
runs-on: windows-latest
timeout-minutes: 5
steps:
- name: Runner check
shell: powershell
run: |
Write-Host "Runner OK on $env:COMPUTERNAME"
Write-Host "OS: $([System.Environment]::OSVersion.VersionString)"
Write-Host "PowerShell: $($PSVersionTable.PSVersion)"
$py = Get-Command py -ErrorAction SilentlyContinue
if ($py) { & py -3.11 --version } else { Write-Host "No py launcher; build will self-install Python 3.11." }
build-windows: build-windows:
needs: [preflight]
runs-on: windows-latest runs-on: windows-latest
timeout-minutes: 30 timeout-minutes: 30
steps: steps:
@@ -24,9 +41,10 @@ jobs:
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Ensure Python 3.11 - name: Ensure Python 3.11
shell: pwsh shell: powershell
run: | run: |
$ErrorActionPreference = 'Stop' $ErrorActionPreference = 'Stop'
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$python = $null $python = $null
# 1) Existing "py -3.11" launcher # 1) Existing "py -3.11" launcher
@@ -50,7 +68,7 @@ jobs:
Write-Host "Python 3.11 not found - installing per-user..." Write-Host "Python 3.11 not found - installing per-user..."
$tmp = if ($env:RUNNER_TEMP) { $env:RUNNER_TEMP } else { $env:TEMP } $tmp = if ($env:RUNNER_TEMP) { $env:RUNNER_TEMP } else { $env:TEMP }
$installer = Join-Path $tmp "python-3.11.9-amd64.exe" $installer = Join-Path $tmp "python-3.11.9-amd64.exe"
Invoke-WebRequest -Uri "https://www.python.org/ftp/python/3.11.9/python-3.11.9-amd64.exe" -OutFile $installer Invoke-WebRequest -UseBasicParsing -Uri "https://www.python.org/ftp/python/3.11.9/python-3.11.9-amd64.exe" -OutFile $installer
$dir = Join-Path $tmp "Python311" $dir = Join-Path $tmp "Python311"
$proc = Start-Process -FilePath $installer -Wait -PassThru -NoNewWindow -ArgumentList @( $proc = Start-Process -FilePath $installer -Wait -PassThru -NoNewWindow -ArgumentList @(
"/quiet","InstallAllUsers=0","PrependPath=0","Include_launcher=0","Include_test=0","TargetDir=$dir" "/quiet","InstallAllUsers=0","PrependPath=0","Include_launcher=0","Include_test=0","TargetDir=$dir"
@@ -61,24 +79,26 @@ jobs:
if (-not (Test-Path $python)) { throw "Python not found at '$python'" } if (-not (Test-Path $python)) { throw "Python not found at '$python'" }
& $python --version & $python --version
"PYTHON=$python" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8 # Write to GITHUB_ENV without a BOM (ascii) so the value parses cleanly.
Add-Content -Path $env:GITHUB_ENV -Value "PYTHON=$python" -Encoding ascii
- name: Install dependencies - name: Install dependencies
shell: pwsh shell: powershell
run: | run: |
$ErrorActionPreference = 'Stop' $ErrorActionPreference = 'Stop'
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
& $env:PYTHON -m pip install --upgrade pip & $env:PYTHON -m pip install --upgrade pip
& $env:PYTHON -m pip install -e . & $env:PYTHON -m pip install -e .
& $env:PYTHON -m pip install pyinstaller & $env:PYTHON -m pip install pyinstaller
- name: Build Windows executable - name: Build Windows executable
shell: pwsh shell: powershell
run: | run: |
$ErrorActionPreference = 'Stop' $ErrorActionPreference = 'Stop'
& $env:PYTHON -m PyInstaller --noconfirm macropad.spec & $env:PYTHON -m PyInstaller --noconfirm macropad.spec
- name: Verify build output - name: Verify build output
shell: pwsh shell: powershell
run: | run: |
if (-not (Test-Path dist/macropad.exe)) { if (-not (Test-Path dist/macropad.exe)) {
throw "Build failed: dist/macropad.exe not found" throw "Build failed: dist/macropad.exe not found"
@@ -94,11 +114,12 @@ jobs:
- name: Publish release asset (tags only) - name: Publish release asset (tags only)
if: startsWith(github.ref, 'refs/tags/') if: startsWith(github.ref, 'refs/tags/')
shell: pwsh shell: powershell
env: env:
GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: | run: |
$ErrorActionPreference = 'Stop' $ErrorActionPreference = 'Stop'
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$api = $env:GITHUB_API_URL $api = $env:GITHUB_API_URL
$repo = $env:GITHUB_REPOSITORY $repo = $env:GITHUB_REPOSITORY
$tag = $env:GITHUB_REF_NAME $tag = $env:GITHUB_REF_NAME