Build Standalone Application #36
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 Standalone Application | |
| on: | |
| # Manual trigger | |
| workflow_dispatch: | |
| # Key: Give GITHUB_TOKEN write permissions (contents: write), otherwise unable to create releases | |
| permissions: | |
| contents: write | |
| jobs: | |
| build_and_release: | |
| runs-on: macos-latest | |
| steps: | |
| # 1. Check out repository code | |
| - name: Check out repository | |
| uses: actions/checkout@v2 | |
| # 2. Set up Python 3.11 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| # 3. Verify Python framework installation | |
| - name: Verify Python framework | |
| run: | | |
| echo "Python version:" | |
| python --version | |
| echo "Python executable path:" | |
| which python | |
| echo "Python framework location:" | |
| python -c "import sys; print(sys.prefix)" | |
| echo "Available Python frameworks:" | |
| ls -la /Library/Frameworks/Python.framework/Versions/ || echo "No Python frameworks found in /Library/Frameworks" | |
| # 4. Install dependencies | |
| - name: Install dependencies | |
| run: | | |
| # Clear pip cache to avoid Python version conflicts | |
| pip cache purge || true | |
| # Upgrade pip | |
| pip install --upgrade pip | |
| # Install dependencies with no cache to ensure fresh build against Python 3.11 | |
| pip install --no-cache-dir -r requirements.txt | |
| pip install --no-cache-dir py2app | |
| # Install librsvg for SVG conversion | |
| brew install librsvg | |
| # 5. Create app icon from SVG | |
| - name: Create app icon from SVG | |
| run: | | |
| # Create different sizes of PNG | |
| rsvg-convert -w 16 -h 16 icon.svg -o icon_16x16.png | |
| rsvg-convert -w 32 -h 32 icon.svg -o icon_32x32.png | |
| rsvg-convert -w 64 -h 64 icon.svg -o icon_64x64.png | |
| rsvg-convert -w 128 -h 128 icon.svg -o icon_128x128.png | |
| rsvg-convert -w 256 -h 256 icon.svg -o icon_256x256.png | |
| rsvg-convert -w 512 -h 512 icon.svg -o icon_512x512.png | |
| rsvg-convert -w 1024 -h 1024 icon.svg -o icon_1024x1024.png | |
| # Create iconset directory structure | |
| mkdir icon.iconset | |
| cp icon_16x16.png icon.iconset/icon_16x16.png | |
| cp icon_32x32.png icon.iconset/icon_16x16@2x.png | |
| cp icon_32x32.png icon.iconset/icon_32x32.png | |
| cp icon_64x64.png icon.iconset/icon_32x32@2x.png | |
| cp icon_128x128.png icon.iconset/icon_128x128.png | |
| cp icon_256x256.png icon.iconset/icon_128x128@2x.png | |
| cp icon_256x256.png icon.iconset/icon_256x256.png | |
| cp icon_512x512.png icon.iconset/icon_256x256@2x.png | |
| cp icon_512x512.png icon.iconset/icon_512x512.png | |
| cp icon_1024x1024.png icon.iconset/icon_512x512@2x.png | |
| # Use iconutil to create .icns file | |
| iconutil -c icns icon.iconset | |
| # Verify icon file creation success | |
| ls -la icon.icns | |
| # 6. Create setup.py configuration file | |
| - name: Create setup.py for py2app | |
| run: | | |
| cat > setup.py << 'EOF' | |
| from setuptools import setup | |
| import sys | |
| APP = ['everything.py'] | |
| DATA_FILES = [ | |
| ('', ['LICENSE.md', 'README.md']), | |
| ] | |
| OPTIONS = { | |
| 'argv_emulation': False, | |
| 'packages': ['PyQt6'], | |
| 'excludes': [], | |
| 'iconfile': 'icon.icns', | |
| 'plist': { | |
| 'CFBundleName': 'Everything', | |
| 'CFBundleDisplayName': 'Everything', | |
| 'CFBundleVersion': '1.4.2', | |
| 'CFBundleShortVersionString': '1.4.2', | |
| 'CFBundleIdentifier': 'com.appledragon.everythingbymdfind', | |
| 'LSMinimumSystemVersion': '10.14', | |
| 'NSHighResolutionCapable': True, | |
| }, | |
| # Use alias mode to avoid copying Python framework | |
| 'alias': False, | |
| # This ensures we use the installed Python and don't try to bundle multiple versions | |
| 'strip': True, | |
| 'optimize': 2, | |
| } | |
| setup( | |
| app=APP, | |
| data_files=DATA_FILES, | |
| options={'py2app': OPTIONS}, | |
| setup_requires=['py2app'], | |
| ) | |
| EOF | |
| # 7. Build universal application | |
| - name: Build universal application | |
| env: | |
| ARCHFLAGS: "-arch x86_64 -arch arm64" | |
| run: | | |
| # Clean previous builds | |
| rm -rf build dist | |
| # Debug: Show Python and PyQt6 information | |
| echo "=== Python Information ===" | |
| python --version | |
| python -c "import sys; print('Python prefix:', sys.prefix)" | |
| python -c "import sys; print('Python executable:', sys.executable)" | |
| echo "=== PyQt6 Information ===" | |
| python -c "import PyQt6; print('PyQt6 location:', PyQt6.__file__)" | |
| python -c "import PyQt6.QtCore; print('Qt version:', PyQt6.QtCore.qVersion())" | |
| # Build universal version (supports both x86_64 and arm64) | |
| # Using --no-strip to preserve debugging symbols and see what's included | |
| python setup.py py2app --arch universal2 2>&1 | tee build.log || { | |
| echo "=== Build failed, showing last 100 lines of output ===" | |
| tail -100 build.log | |
| exit 1 | |
| } | |
| # Create archive | |
| cd dist | |
| zip -r ../everything.zip "Everything.app" | |
| cd .. | |
| # 8. Create GitHub Release | |
| - name: Create GitHub release | |
| id: create_release | |
| uses: actions/create-release@v1 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| with: | |
| tag_name: 'v1.4.1' | |
| release_name: 'v1.4.1' | |
| draft: false | |
| prerelease: false | |
| # 9. Upload release asset | |
| - name: Upload release asset | |
| uses: actions/upload-release-asset@v1 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| with: | |
| upload_url: ${{ steps.create_release.outputs.upload_url }} | |
| asset_path: everything.zip | |
| asset_name: everything.zip | |
| asset_content_type: application/zip |