Skip to content

chore(release): prepare 0.54.0 (#187) #32

chore(release): prepare 0.54.0 (#187)

chore(release): prepare 0.54.0 (#187) #32

name: Build Windows native installer
on:
push:
tags:
# Match the existing PyPI release workflow's tag scheme: v<MAJOR>.<MINOR>.<PATCH>.
- "v[0-9]+.[0-9]+.[0-9]+"
workflow_dispatch:
inputs:
version:
description: "Version to build (e.g. 0.27.0)"
required: true
type: string
concurrency:
group: windows-installer-${{ github.ref }}
cancel-in-progress: false
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
jobs:
build:
runs-on: windows-latest
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pinned from v6.0.2
- name: Resolve version
id: ver
shell: pwsh
env:
GITHUB_REF: ${{ github.ref }}
INPUT_VERSION: ${{ inputs.version }}
run: |
if ($env:GITHUB_REF -match '^refs/tags/v([0-9]+\.[0-9]+\.[0-9]+)$') {
"version=$($Matches[1])" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
} elseif ($env:INPUT_VERSION) {
"version=$($env:INPUT_VERSION)" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
} else {
throw "No version source"
}
- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pinned from v6.2.0
with:
python-version: "3.13"
- name: Install uv
run: pip install uv
- name: Sync project dependencies
run: uv sync --frozen --no-dev
- name: Set up Node.js (web build)
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # pinned from v6.4.0
with:
node-version: "24"
cache: "npm"
cache-dependency-path: web/package-lock.json
# The web/dashboard frontends are gitignored build artifacts; without these
# steps PyInstaller froze a binary whose web UI 404'd on "/". The spec
# file now also refuses to freeze when the bundles are missing.
- name: Build web UI bundle
env:
PYTHINKER_WEB_STRICT_VERSION: "1"
PYTHINKER_WEB_EXPECT_VERSION: ${{ steps.ver.outputs.version }}
run: python scripts/build_web.py
- name: Build dashboard UI bundle
run: python scripts/build_dashboard.py
- name: Install PyInstaller
run: uv pip install pyinstaller
- name: Generate icon (from logo.png)
shell: pwsh
run: |
choco install -y imagemagick.tool --no-progress | Out-Null
$logo = "docs/media/logo.png"
if (-not (Test-Path $logo)) {
throw "Expected logo source at $logo; cannot generate installer icon."
}
magick $logo -define icon:auto-resize=16,32,48,256 `
"packages/windows-installer/assets/pythinker.ico"
if ($LASTEXITCODE -ne 0) { throw "ImageMagick icon generation failed" }
- name: Install Inno Setup
run: choco install -y innosetup --no-progress
- name: Build installer
shell: pwsh
env:
WINDOWS_CERT_PFX_BASE64: ${{ secrets.WINDOWS_CERT_PFX_BASE64 }}
WINDOWS_CERT_PASSWORD: ${{ secrets.WINDOWS_CERT_PASSWORD }}
BUILD_VERSION: ${{ steps.ver.outputs.version }}
run: |
$py = (& uv run python -c "import sys; print(sys.executable)").Trim()
pwsh packages/windows-installer/build.ps1 -Version $env:BUILD_VERSION -Python $py
- name: Upload artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pinned from v7.0.1
with:
name: PythinkerSetup-${{ steps.ver.outputs.version }}
path: |
dist/PythinkerSetup-*.exe
dist/PythinkerSetup-*.exe.sha256
- name: Attach to Release (create-or-update)
if: startsWith(github.ref, 'refs/tags/v')
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # pinned from v3.0.0
with:
tag_name: ${{ github.ref_name }}
# All platform workflows race to create this Release on the same tag.
# Mark it prerelease so it stays OUT of /releases/latest (which is
# date-based and ignores make_latest) until every platform asset has
# uploaded. promote-release.yml clears prerelease and sets make_latest
# once all expected assets are attached, so the install scripts and
# the in-app updater never resolve a version whose asset is in flight.
prerelease: "true"
fail_on_unmatched_files: false
make_latest: "false"
files: |
dist/PythinkerSetup-*.exe
dist/PythinkerSetup-*.exe.sha256
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}