CI: build cross-platform binaries + tagged release
.gitea/workflows/release.yml builds the PySide6 GUI with PyInstaller on each self-hosted runner and, on a v* tag, publishes a Gitea Release with every platform binary attached: - windows-latest -> OBDash-windows.exe (onefile, --windowed) - self-hosted-mac -> OBDash-macos.zip (.app bundle, ditto-zipped) - docker (linux) -> OBDash-linux-x86_64 (onefile + patchelf/GL libs) - arm64 (Pi) -> OBDash-linux-aarch64 Uses softprops/action-gh-release with the auto GITEA_TOKEN; manual dispatch build-only (no release). profiles/ is bundled via --add-data; obdcore.profile.profiles_dir() now resolves sys._MEIPASS when frozen so the binary finds its vehicle profiles. Validated locally on Linux: PyInstaller onefile builds (88MB), launches offscreen, and loads bundled profiles (6 found). Build artifacts gitignored. Added .claude/gitea-ship.json. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016yT89n4zR4qbrySoSiEyZs
This commit is contained in:
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"owner": "justin",
|
||||||
|
"runner_label": "windows-latest | self-hosted-mac | docker | arm64",
|
||||||
|
"deploy": "git-tag-release",
|
||||||
|
"version_source": "git-tag",
|
||||||
|
"notes": "Open-source desktop app (PySide6/pyqtgraph). CI = .gitea/workflows/release.yml builds PyInstaller binaries on the Windows / self-hosted-mac / docker (linux x86_64) / arm64 (Pi) runners; on a v* tag it publishes a Gitea Release with each platform binary attached (softprops/action-gh-release, GITEA_TOKEN). No containers/registry/Watchtower. Profiles are bundled via --add-data and found at runtime via sys._MEIPASS (obdcore/profile.py profiles_dir())."
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
name: Build binaries
|
||||||
|
|
||||||
|
# Build OBDash GUI binaries on each self-hosted runner. On a version tag
|
||||||
|
# (v*), publish a Gitea Release with every platform's binary attached.
|
||||||
|
# Manual runs (workflow_dispatch) build-only (no release) to verify compilation.
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags: ["v*"]
|
||||||
|
workflow_dispatch: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
windows:
|
||||||
|
runs-on: windows-latest # self-hosted Windows runner
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: "3.12"
|
||||||
|
- name: Build OBDash.exe (PyInstaller)
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install -r requirements-gui.txt pyinstaller
|
||||||
|
pyinstaller --noconfirm --onefile --windowed --name OBDash --add-data "profiles;profiles" run_gui.py
|
||||||
|
Copy-Item dist/OBDash.exe OBDash-windows.exe
|
||||||
|
- name: Publish to release
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
files: OBDash-windows.exe
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
|
||||||
|
macos:
|
||||||
|
runs-on: self-hosted-mac
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Build OBDash.app (PyInstaller)
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
python3 -m venv .build-venv
|
||||||
|
. .build-venv/bin/activate
|
||||||
|
pip install --upgrade pip
|
||||||
|
pip install -r requirements-gui.txt pyinstaller
|
||||||
|
pyinstaller --noconfirm --windowed --name OBDash --add-data "profiles:profiles" run_gui.py
|
||||||
|
ditto -c -k --keepParent dist/OBDash.app OBDash-macos.zip
|
||||||
|
- name: Publish to release
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
files: OBDash-macos.zip
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
|
||||||
|
linux-amd64:
|
||||||
|
runs-on: docker # Linux x86_64 runner (container)
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Build OBDash (PyInstaller)
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
# patchelf is needed for onefile; GL/EGL/xkb are runtime deps users need
|
||||||
|
(sudo apt-get update && sudo apt-get install -y python3-venv patchelf libgl1 libegl1 libxkbcommon0) \
|
||||||
|
|| (apt-get update && apt-get install -y python3-venv patchelf libgl1 libegl1 libxkbcommon0) || true
|
||||||
|
python3 -m venv .build-venv
|
||||||
|
. .build-venv/bin/activate
|
||||||
|
pip install --upgrade pip
|
||||||
|
pip install -r requirements-gui.txt pyinstaller
|
||||||
|
pyinstaller --noconfirm --onefile --name OBDash --add-data "profiles:profiles" run_gui.py
|
||||||
|
cp dist/OBDash OBDash-linux-x86_64
|
||||||
|
- name: Publish to release
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
files: OBDash-linux-x86_64
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
|
||||||
|
linux-arm64:
|
||||||
|
runs-on: arm64 # Raspberry Pi (aarch64) runner
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Build OBDash (PyInstaller)
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
(sudo apt-get update && sudo apt-get install -y python3-venv patchelf libgl1 libegl1 libxkbcommon0) \
|
||||||
|
|| (apt-get update && apt-get install -y python3-venv patchelf libgl1 libegl1 libxkbcommon0) || true
|
||||||
|
python3 -m venv .build-venv
|
||||||
|
. .build-venv/bin/activate
|
||||||
|
pip install --upgrade pip
|
||||||
|
pip install -r requirements-gui.txt pyinstaller
|
||||||
|
pyinstaller --noconfirm --onefile --name OBDash --add-data "profiles:profiles" run_gui.py
|
||||||
|
cp dist/OBDash OBDash-linux-aarch64
|
||||||
|
- name: Publish to release
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
files: OBDash-linux-aarch64
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||||
@@ -1,3 +1,8 @@
|
|||||||
__pycache__/
|
__pycache__/
|
||||||
*.pyc
|
*.pyc
|
||||||
.venv/
|
.venv/
|
||||||
|
|
||||||
|
# PyInstaller build output
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
*.spec
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ JSON schema (schema=1):
|
|||||||
import glob
|
import glob
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
from .formula import compile_formula
|
from .formula import compile_formula
|
||||||
@@ -42,6 +43,11 @@ class Profile:
|
|||||||
|
|
||||||
|
|
||||||
def profiles_dir():
|
def profiles_dir():
|
||||||
|
# In a PyInstaller bundle, profiles/ is added as data and unpacked under
|
||||||
|
# sys._MEIPASS; otherwise it's the repo's profiles/ next to obdcore/.
|
||||||
|
if getattr(sys, "frozen", False):
|
||||||
|
base = getattr(sys, "_MEIPASS", os.path.dirname(sys.executable))
|
||||||
|
return os.path.join(base, "profiles")
|
||||||
return os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
|
return os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
|
||||||
"profiles")
|
"profiles")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user