Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 146 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@
# follow-up. The smoke step here is structural -- it invokes the
# bundled binary with ``--version`` and asserts it prints the package
# version.
#
# In addition to the raw archive (.zip/.tar.gz), each job builds a real
# per-OS installer from inputs under ``packaging/``:
# * Windows -> Inno Setup .exe (packaging/windows/exlab-wizard.iss)
# * macOS -> .dmg (create-dmg, with an hdiutil fallback)
# * Linux -> AppImage (packaging/linux/AppRun + exlab-wizard.desktop)
# On a published release every produced asset is attached to that release.
# Installers do NOT register OS autostart -- the app manages its own
# autostart at runtime (in-app AutostartManager).

name: build

Expand All @@ -35,6 +44,11 @@ on:
types: [published]
workflow_dispatch:

# Release assets are uploaded from the matrix job, which needs write
# access to the repository contents (releases).
permissions:
contents: write

# Auto-cancel superseded runs on the same branch / PR. When a new commit
# lands, any in-flight or queued run on the older SHA is cancelled so we
# don't burn macOS minutes on stale builds.
Expand Down Expand Up @@ -107,20 +121,23 @@ jobs:
test "$actual_version" = "$expected_version"

- name: Package artifact
id: package
shell: bash
run: |
set -euo pipefail
version=$(python -c "from exlab_wizard import __version__; print(__version__)")
out_name="ExLab-Wizard-${version}-${{ matrix.artifact_suffix }}"
echo "version=${version}" >> "$GITHUB_OUTPUT"
echo "out_name=${out_name}" >> "$GITHUB_OUTPUT"
case "${{ matrix.os }}" in
windows-latest)
cd dist
7z a -tzip "../${out_name}.zip" "ExLab-Wizard"
cd ..
;;
macos-*)
# v1 ships an unsigned ``.app`` directory inside a tar;
# a real ``.dmg`` is a v1.1 follow-up (Backend Spec §15.2).
# Raw unsigned ``.app`` directory inside a tar; the .dmg is
# produced by a dedicated step below.
cd dist
tar -czf "../${out_name}.tar.gz" "ExLab-Wizard.app"
cd ..
Expand All @@ -133,12 +150,139 @@ jobs:
esac
ls -lh ExLab-Wizard-* || true

# --- Installer: Windows (Inno Setup .exe) ------------------------------
- name: Install Inno Setup (Windows)
if: matrix.os == 'windows-latest'
shell: bash
run: choco install innosetup -y --no-progress

- name: Download WebView2 bootstrapper (Windows)
if: matrix.os == 'windows-latest'
shell: bash
run: |
set -euo pipefail
curl -fSL -o packaging/windows/MicrosoftEdgeWebview2Setup.exe \
"https://go.microsoft.com/fwlink/p/?LinkId=2124703"

- name: Build Inno Setup installer (Windows)
if: matrix.os == 'windows-latest'
shell: bash
run: |
set -euo pipefail
version="${{ steps.package.outputs.version }}"
# choco installs ISCC.exe but does not add it to the current shell's
# PATH, so resolve it explicitly (known install dir, then a search).
iscc="/c/Program Files (x86)/Inno Setup 6/ISCC.exe"
if [ ! -f "$iscc" ]; then
iscc="$(find "/c/Program Files (x86)" "/c/Program Files" -name ISCC.exe 2>/dev/null | head -n 1)"
fi
if [ -z "${iscc:-}" ] || [ ! -f "$iscc" ]; then
echo "ISCC.exe not found after choco install innosetup" >&2
exit 1
fi
# Git-bash rewrites a leading-slash arg like "/DAppVersion=..." into a
# Windows path, so ISCC sees it as a second script filename. Disable
# MSYS path conversion for this call; the .iss path is relative and so
# is left untouched.
MSYS_NO_PATHCONV=1 "$iscc" "/DAppVersion=${version}" packaging/windows/exlab-wizard.iss
ls -lh "ExLab-Wizard-${version}-win-x64-setup.exe"

# --- Installer: macOS (.dmg) -------------------------------------------
- name: Install create-dmg (macOS)
if: matrix.os == 'macos-14'
run: brew install create-dmg

- name: Build DMG (macOS)
if: matrix.os == 'macos-14'
shell: bash
run: |
set -uo pipefail
version="${{ steps.package.outputs.version }}"
dmg="ExLab-Wizard-${version}-mac-arm64.dmg"
rm -f "$dmg"
# create-dmg can be flaky on headless CI; retry once, then fall
# back to a plain hdiutil image so packaging never hard-fails.
make_dmg() {
create-dmg \
--volname "ExLab-Wizard" \
--app-drop-link 450 180 \
--icon "ExLab-Wizard.app" 150 180 \
--no-internet-enable \
"$dmg" "dist/ExLab-Wizard.app"
}
if ! make_dmg; then
echo "create-dmg failed, retrying once..." >&2
rm -f "$dmg"
if ! make_dmg; then
echo "create-dmg failed twice; falling back to hdiutil..." >&2
rm -f "$dmg"
staging="$(mktemp -d)"
cp -R "dist/ExLab-Wizard.app" "$staging/"
ln -s /Applications "$staging/Applications"
hdiutil create -volname "ExLab-Wizard" -srcfolder "$staging" \
-ov -format UDZO "$dmg"
rm -rf "$staging"
fi
fi
ls -lh "$dmg"

# --- Installer: Linux (AppImage) ---------------------------------------
- name: Build AppImage (Linux)
if: matrix.os == 'ubuntu-latest'
shell: bash
env:
ARCH: x86_64
APPIMAGE_EXTRACT_AND_RUN: "1"
run: |
set -euo pipefail
version="${{ steps.package.outputs.version }}"
out="ExLab-Wizard-${version}-linux-x64.AppImage"

curl -fSL -o appimagetool \
"https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage"
chmod +x appimagetool

rm -rf AppDir
mkdir -p AppDir/usr/bin
# Drop the whole onedir bundle in; AppRun execs the CLI alias inside it.
cp -R dist/ExLab-Wizard AppDir/usr/bin/ExLab-Wizard

cp packaging/linux/AppRun AppDir/AppRun
chmod +x AppDir/AppRun
cp packaging/linux/exlab-wizard.desktop AppDir/exlab-wizard.desktop

if [ -f assets/icons/ExLabWizard.png ]; then
cp assets/icons/ExLabWizard.png AppDir/exlab-wizard.png
else
# No app icon present -- write a 1x1 PNG placeholder so that
# appimagetool (which requires an icon) still succeeds.
printf '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x06\x00\x00\x00\x1f\x15\xc4\x89\x00\x00\x00\rIDATx\x9cc````\x00\x00\x00\x05\x00\x01\xa5\xf6E@\x00\x00\x00\x00IEND\xaeB`\x82' > AppDir/exlab-wizard.png
fi

./appimagetool AppDir "$out"
ls -lh "$out"

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: exlab-wizard-${{ matrix.artifact_suffix }}
path: |
ExLab-Wizard-*.zip
ExLab-Wizard-*.tar.gz
ExLab-Wizard-*-setup.exe
ExLab-Wizard-*.dmg
ExLab-Wizard-*.AppImage
if-no-files-found: error
retention-days: 30

# On a published release, attach every asset this job produced (raw
# archive + installer) to the already-published release. Each matrix
# job appends its own files to the same release.
- name: Attach assets to release
if: github.event_name == 'release'
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.event.release.tag_name }}
fail_on_unmatched_files: true
files: |
ExLab-Wizard-*
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,5 @@ tests/docker/nas-data/*

# superpowers brainstorming visual companion
.superpowers/
graphify-out/
/graphify-out/
/*.png
15 changes: 10 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,16 @@ runtime-only install drop the extra: `uv sync` / `pip install -e .`.

### Pre-built binary

For each tagged release, the `build` workflow publishes single-folder
PyInstaller artifacts under
[Releases](../../releases) (`linux-x64`, `win-x64`, `mac-arm64`).
Unpack and run the platform-specific entry point under `ExLab-Wizard/`
(or `ExLab-Wizard.app/` on macOS).
Every tagged release publishes a GitHub Release that carries per-OS installers —
a Windows `.exe` installer, a macOS `.dmg`, and a Linux `.AppImage` — plus raw
archives for each platform under [Releases](../../releases). Download the
installer (or archive) for your platform from the
[latest release](https://github.com/exfab/ExLabWizard/releases/latest) and run it.

On startup ExLab-Wizard checks GitHub for a newer release; when one is found it
raises an OS notification and the tray menu gains a "Check for updates…" item
that opens the releases page. This probe can be disabled with
`update_check.enabled: false` in `config.yaml`.

## Running ExLab-Wizard

Expand Down
2 changes: 1 addition & 1 deletion assets/ExLabWizardLogo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion assets/sync_cloud.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading