refactor: update shortcut for blur detection action from Ctrl+B to B … #21
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build Desktop Binaries | |
| on: | |
| workflow_dispatch: | |
| push: | |
| tags: | |
| - 'v*' | |
| permissions: | |
| contents: write | |
| concurrency: | |
| group: release-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| build: | |
| name: ${{ matrix.os }} PyInstaller build | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 60 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: windows-latest | |
| python: '3.12' | |
| artifact_name: PhotoSort-Windows-x64 | |
| onnx_runtime: onnxruntime | |
| - os: windows-latest | |
| python: '3.12' | |
| artifact_name: PhotoSort-Windows-x64-CUDA | |
| onnx_runtime: onnxruntime-gpu | |
| - os: macos-13 # Intel | |
| python: '3.12' | |
| artifact_name: PhotoSort-macOS-Intel | |
| - os: macos-14 # Apple Silicon | |
| python: '3.12' | |
| artifact_name: PhotoSort-macOS-AppleSilicon | |
| env: | |
| PIP_DISABLE_PIP_VERSION_CHECK: '1' | |
| PIP_NO_PYTHON_VERSION_WARNING: '1' | |
| PIP_PROGRESS_BAR: 'off' | |
| QT_QPA_PLATFORM: offscreen | |
| # Enable file logging in packaged app for troubleshooting | |
| PHOTOSORT_ENABLE_FILE_LOGGING: 'true' | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python }} | |
| - name: Generate version module | |
| shell: bash | |
| # Write src/core/build_info.py VERSION from tag (strip leading 'v') or short SHA for ad-hoc builds | |
| run: | | |
| python - <<'PY' | |
| import os, re, pathlib | |
| ref = os.getenv('GITHUB_REF', '') or '' | |
| sha = (os.getenv('GITHUB_SHA', '') or '')[:7] | |
| m = re.match(r'refs/tags/v?(.*)$', ref) | |
| if m and m.group(1): | |
| version = m.group(1) | |
| else: | |
| version = f'dev-{sha}' if sha else 'dev' | |
| path = pathlib.Path('src') / 'core' / 'build_info.py' | |
| path.parent.mkdir(parents=True, exist_ok=True) | |
| content = '# File auto-generated by CI. Do not edit.\nVERSION = ' + repr(version) + '\n' | |
| path.write_text(content, encoding='utf-8') | |
| print('Wrote', path, 'with version:', version) | |
| PY | |
| - name: Cache pip | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.cache/pip | |
| key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt', '**/requirements-dev.txt') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pip- | |
| - name: Install Python deps | |
| shell: bash | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -r requirements.txt | |
| # Override ONNX Runtime with matrix-specified package | |
| if [ "$RUNNER_OS" = "Windows" ]; then | |
| pip install --force-reinstall ${{ matrix.onnx_runtime }} | |
| fi | |
| # Build tools | |
| pip install pyinstaller | |
| - name: Generate app icons (platform-specific) | |
| shell: bash | |
| run: | | |
| # Use committed assets/app_icon.png | |
| mkdir -p assets | |
| if [ "$RUNNER_OS" = "macOS" ]; then | |
| if [ ! -f assets/photosort.icns ] || [ assets/app_icon.png -nt assets/photosort.icns ]; then | |
| mkdir -p build/icons/PhotoSort.iconset | |
| python - <<'PY' | |
| import os | |
| from PIL import Image | |
| base = Image.open('assets/app_icon.png') | |
| sizes = { | |
| 'icon_16x16.png': 16, | |
| 'icon_16x16@2x.png': 32, | |
| 'icon_32x32.png': 32, | |
| 'icon_32x32@2x.png': 64, | |
| 'icon_128x128.png': 128, | |
| 'icon_128x128@2x.png': 256, | |
| 'icon_256x256.png': 256, | |
| 'icon_256x256@2x.png': 512, | |
| 'icon_512x512.png': 512, | |
| 'icon_512x512@2x.png': 1024, | |
| } | |
| os.makedirs('build/icons/PhotoSort.iconset', exist_ok=True) | |
| for name, sz in sizes.items(): | |
| base.resize((sz, sz), Image.LANCZOS).save(os.path.join('build/icons/PhotoSort.iconset', name)) | |
| PY | |
| iconutil -c icns build/icons/PhotoSort.iconset -o assets/photosort.icns | |
| fi | |
| fi | |
| - name: Ensure models dir exists | |
| shell: bash | |
| run: | | |
| mkdir -p models | |
| - name: Build with PyInstaller (Windows) | |
| if: runner.os == 'Windows' | |
| run: | | |
| pyinstaller -w --onefile -n PhotoSort ` | |
| --icon assets/app_icon.ico ` | |
| --paths src ` | |
| --hidden-import core.build_info ` | |
| --add-data "src/ui/dark_theme.qss;." ` | |
| --add-data "assets/app_icon.ico;." ` | |
| --add-data "assets/app_icon.png;." ` | |
| --hidden-import pyexiv2 ` | |
| --hidden-import PyQt6.QtCore ` | |
| --hidden-import PyQt6.QtGui ` | |
| --hidden-import PyQt6.QtWidgets ` | |
| --hidden-import rawpy ` | |
| --hidden-import cv2 ` | |
| --hidden-import onnxruntime ` | |
| --hidden-import torchvision ` | |
| --hidden-import torch ` | |
| --hidden-import sklearn ` | |
| --hidden-import sentence_transformers ` | |
| --add-data "models;models" ` | |
| --runtime-hook runtime_hook.py ` | |
| src/main.py | |
| - name: Collect artifact (Windows .exe) | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| $exe = "${{ matrix.artifact_name }}.exe" | |
| Copy-Item "dist\PhotoSort.exe" $exe -Force | |
| - name: Generate SHA256 checksum (Windows) | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| $exe = "${{ matrix.artifact_name }}.exe" | |
| $hash = (Get-FileHash -Algorithm SHA256 $exe).Hash.ToLower() | |
| "$hash $exe" | Out-File -Encoding ascii "$exe.sha256" | |
| - name: Build with PyInstaller (macOS) | |
| if: runner.os == 'macOS' | |
| run: | | |
| pyinstaller -w --name PhotoSort \ | |
| --icon assets/photosort.icns \ | |
| --paths src \ | |
| --hidden-import core.build_info \ | |
| --add-data src/ui/dark_theme.qss:. \ | |
| --add-data assets/app_icon.ico:. \ | |
| --add-data assets/app_icon.png:. \ | |
| --hidden-import PyQt6.QtCore \ | |
| --hidden-import PyQt6.QtGui \ | |
| --hidden-import PyQt6.QtWidgets \ | |
| --hidden-import rawpy \ | |
| --hidden-import pyexiv2 \ | |
| --hidden-import cv2 \ | |
| --hidden-import onnxruntime \ | |
| --hidden-import torchvision \ | |
| --hidden-import torch \ | |
| --hidden-import sklearn \ | |
| --hidden-import sentence_transformers \ | |
| --add-data models:models \ | |
| src/main.py | |
| - name: Package artifact (macOS .dmg) | |
| if: runner.os == 'macOS' | |
| shell: bash | |
| run: | | |
| DMG="${{ matrix.artifact_name }}.dmg" | |
| APP_PATH="dist/PhotoSort.app" | |
| if [ -d "$APP_PATH" ]; then | |
| hdiutil create -volname "PhotoSort" -srcfolder "$APP_PATH" -ov -format UDZO "$DMG" | |
| else | |
| echo "PhotoSort.app not found in dist" >&2 | |
| exit 1 | |
| fi | |
| - name: Generate SHA256 checksum (macOS) | |
| if: runner.os == 'macOS' | |
| shell: bash | |
| run: | | |
| DMG="${{ matrix.artifact_name }}.dmg" | |
| shasum -a 256 "$DMG" > "$DMG.sha256" | |
| - name: Archive artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.artifact_name }} | |
| path: ${{ matrix.artifact_name }}.* | |
| retention-days: 14 | |
| release: | |
| if: startsWith(github.ref, 'refs/tags/') | |
| needs: build | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Download artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: artifacts | |
| - name: Create Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| files: | | |
| artifacts/** | |
| draft: false | |
| prerelease: false | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |