build: add single-command release script + portable zip artifacts
One-developer workflow: ``python build/make_release.py`` on each target OS produces both the installer and a portable .zip for that platform. Preflight checks PyInstaller / Pillow / iscc / hdiutil / ditto / appimagetool and bails with install hints if anything is missing — no half-built dist/. New scripts: - build/make_release.py — orchestrator, auto-detects host OS. - build/generate_icons.py — icon.ico / icon.icns / icon.png from src/gui/assets/datatools_icon_256.png (Pillow ships ICO + ICNS writers; no platform tooling needed). - build/build_portable_zip.py — Win/Linux portable zip via stdlib. - build/macos/build_zip.sh — Mac portable .app via ditto so bundle metadata survives. installer.iss now adds: Quick Launch task (opt-in, legacy Win 7), App Paths registry entry (Win+R "DataTools" works), SetupIconFile, UninstallDisplayIcon, AppSupportURL, AppUpdatesURL. CI workflow uploads installer + portable per platform and attaches both to GitHub Releases on tag push. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -19,23 +19,53 @@ build/
|
||||
│ Mac .app bundle config. Reads the version
|
||||
│ from src/__init__.py.
|
||||
├── installer.iss Inno Setup script — Windows .exe installer.
|
||||
│ Adds Start Menu + Desktop + App Paths entries.
|
||||
├── generate_icons.py Builds icon.ico / icon.icns / icon.png from
|
||||
│ src/gui/assets/datatools_icon_256.png. Run
|
||||
│ once before pyinstaller (CI does this).
|
||||
├── build_portable_zip.py Cross-platform: zips dist/DataTools/ into a
|
||||
│ no-install portable download. Used by the
|
||||
│ Windows + Linux portable artifacts.
|
||||
├── macos/
|
||||
│ └── build_dmg.sh Wraps dist/DataTools.app into a .dmg with a
|
||||
│ drag-to-/Applications layout.
|
||||
│ ├── build_dmg.sh Wraps dist/DataTools.app into a .dmg with a
|
||||
│ │ drag-to-/Applications layout (installer).
|
||||
│ └── build_zip.sh Wraps dist/DataTools.app into a portable
|
||||
│ .zip via ditto (preserves bundle metadata).
|
||||
├── appimage/
|
||||
│ ├── AppRun Entry point invoked when the AppImage runs.
|
||||
│ ├── datatools.desktop Linux desktop-entry metadata.
|
||||
│ └── build.sh Wraps dist/DataTools/ into an .AppImage.
|
||||
├── hooks/ PyInstaller hooks for libs the static analyser
|
||||
│ └── hook-streamlit.py misses (Streamlit's dynamic imports).
|
||||
├── icon.icns macOS app icon (TODO: produce from a 1024×1024
|
||||
│ PNG. Optional — bundle still builds without).
|
||||
├── icon.ico Windows app icon (TODO).
|
||||
├── icon.png Linux AppImage icon (TODO — build.sh generates
|
||||
│ a placeholder if missing).
|
||||
├── icon.{ico,icns,png} Generated by generate_icons.py — gitignored.
|
||||
└── README.md this file
|
||||
```
|
||||
|
||||
## Distribution outputs per platform
|
||||
|
||||
Each CI run produces two downloads per platform — an installer for
|
||||
buyers who want shortcuts wired automatically, and a portable .zip
|
||||
for buyers (or IT-locked-down machines) that can't run installers:
|
||||
|
||||
| Platform | Installer | Portable |
|
||||
|----------|----------------------------------------|------------------------------------------------|
|
||||
| macOS | `DataTools-<ver>-mac.dmg` | `DataTools-<ver>-mac-portable.zip` (ditto .app)|
|
||||
| Windows | `DataTools-<ver>-win-setup.exe` | `DataTools-<ver>-win-portable.zip` |
|
||||
| Linux | `DataTools-<ver>-linux-x86_64.AppImage`| (the AppImage IS the portable) |
|
||||
|
||||
All six outputs are self-contained: every dependency (Python, pandas,
|
||||
streamlit, pdfplumber, the lot) is frozen into the bundle. The buyer
|
||||
does not need to install Python, pip, or anything else first.
|
||||
|
||||
## Easy-launch surface
|
||||
|
||||
| Affordance | Windows | macOS |
|
||||
|------------------|--------------------------------------------------|------------------------------------------------------|
|
||||
| Desktop shortcut | Inno Setup `desktopicon` task (checked default) | The .app bundle in /Applications is the icon |
|
||||
| App menu | Start Menu → DataTools (always installed) | Launchpad + Spotlight (auto from /Applications) |
|
||||
| Taskbar / Dock | User pins manually (OS forbids programmatic pin) | User pins manually after first launch |
|
||||
| Run from terminal| `DataTools` (registered via App Paths) | `open -a DataTools` (auto from .app bundle) |
|
||||
|
||||
CI: `.github/workflows/build.yml` runs the full pipeline on tag push
|
||||
(matrix: macos-latest, windows-latest, ubuntu-latest) and attaches
|
||||
the resulting installers to a GitHub Release. Manual
|
||||
@@ -43,12 +73,46 @@ the resulting installers to a GitHub Release. Manual
|
||||
|
||||
## Releasing
|
||||
|
||||
### Single-command local build (recommended for one-developer workflow)
|
||||
|
||||
PyInstaller can't cross-compile, so a single machine produces one
|
||||
platform's packages. Run this on each target OS:
|
||||
|
||||
```bash
|
||||
# One-time setup per machine:
|
||||
pip install -r requirements.txt
|
||||
pip install pyinstaller pillow
|
||||
# Windows only: install Inno Setup from https://jrsoftware.org/isdl.php
|
||||
# Linux only: drop appimagetool onto PATH (see preflight output)
|
||||
|
||||
# Build everything for the current OS:
|
||||
python build/make_release.py
|
||||
```
|
||||
|
||||
Outputs land in `dist/`:
|
||||
- Windows host → `DataTools-<ver>-win-setup.exe` + `DataTools-<ver>-win-portable.zip`
|
||||
- macOS host → `DataTools-<ver>-mac.dmg` + `DataTools-<ver>-mac-portable.zip`
|
||||
- Linux host → `DataTools-<ver>-linux-x86_64.AppImage`
|
||||
|
||||
Useful flags:
|
||||
|
||||
```bash
|
||||
python build/make_release.py --preflight # check tooling, build nothing
|
||||
python build/make_release.py --clean # wipe dist/ first
|
||||
python build/make_release.py --skip-installer # just the portable zip
|
||||
python build/make_release.py --skip-portable # just the installer
|
||||
```
|
||||
|
||||
### CI build (push tag → GitHub Release)
|
||||
|
||||
If you have CI runners for all three OSes:
|
||||
|
||||
1. Bump `__version__` in `src/__init__.py`.
|
||||
2. `git commit -am "release: vX.Y.Z" && git tag vX.Y.Z`.
|
||||
3. `git push && git push --tags`.
|
||||
4. CI builds all three platforms and creates a GitHub Release with
|
||||
the installers attached.
|
||||
5. Mirror the GitHub Release assets to Gumroad (manual until v2).
|
||||
4. CI builds all three platforms and creates a Release with the
|
||||
installers + portable zips attached.
|
||||
5. Mirror the Release assets to Gumroad (manual until v2).
|
||||
|
||||
## Signing (Phase 2 — needs accounts/credentials)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user