feat: dynamic versioning and bundled license support #9
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 and Release | |
| on: | |
| push: | |
| branches: [ "**" ] | |
| workflow_dispatch: | |
| permissions: | |
| contents: write | |
| jobs: | |
| create_release: | |
| name: Create Release | |
| runs-on: ubuntu-latest | |
| outputs: | |
| upload_url: ${{ steps.create_release.outputs.upload_url }} | |
| tag_name: ${{ steps.tag_generator.outputs.tag_name }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Generate Tag Name | |
| id: tag_generator | |
| run: | | |
| git fetch --tags | |
| # Get the latest tag, default to v0.0.0 if none exists | |
| LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0") | |
| echo "Latest tag found: $LATEST_TAG" | |
| # Remove 'v' prefix | |
| VERSION=${LATEST_TAG#v} | |
| # Split version into array (assuming vX.Y.Z) | |
| IFS='.' read -r -a parts <<< "$VERSION" | |
| # Calculate new version | |
| if [ ${#parts[@]} -eq 3 ]; then | |
| # Standard X.Y.Z format | |
| MAJOR=${parts[0]} | |
| MINOR=${parts[1]} | |
| PATCH=${parts[2]} | |
| NEW_PATCH=$((PATCH + 1)) | |
| NEW_TAG="v$MAJOR.$MINOR.$NEW_PATCH" | |
| else | |
| # Fail-safe / Initial formatting | |
| NEW_TAG="v0.0.1" | |
| fi | |
| echo "Generated new tag: $NEW_TAG" | |
| echo "tag_name=$NEW_TAG" >> $GITHUB_OUTPUT | |
| - name: Create Release | |
| id: create_release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ steps.tag_generator.outputs.tag_name }} | |
| name: Release ${{ steps.tag_generator.outputs.tag_name }} | |
| draft: false | |
| prerelease: false | |
| generate_release_notes: true | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| build: | |
| name: Build Executable | |
| needs: create_release | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| matrix: | |
| os: [windows-latest, ubuntu-latest, macos-latest] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.10' | |
| - name: Install Dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -r requirements.txt | |
| pip install pyinstaller | |
| - name: Install Linux System Dependencies | |
| if: runner.os == 'Linux' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y python3-tk imagemagick | |
| # Install PyQt6 system dependencies to avoid PyInstaller warnings/errors | |
| sudo apt-get install -y libxcb-cursor0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 libxcb-shape0 libxcb-xkb1 libxcb-util1 libxkbcommon-x11-0 | |
| - name: Build with PyInstaller (Windows) | |
| if: runner.os == 'Windows' | |
| env: | |
| VERSION_TAG: ${{ needs.create_release.outputs.tag_name }} | |
| run: | | |
| # Create version file for dynamic versioning | |
| echo "${{ env.VERSION_TAG }}" > core/version.txt | |
| pyinstaller --name WASP --onefile --windowed --add-data "core;core" --add-data "gui;gui" --add-data "LICENSE;." --add-data "core/version.txt;core" main.py | |
| mv dist/WASP.exe "dist/WASP-${{ env.VERSION_TAG }}-windows.exe" | |
| - name: Build with PyInstaller (Linux - Binary, Deb, AppImage) | |
| if: runner.os == 'Linux' | |
| env: | |
| VERSION_TAG: ${{ needs.create_release.outputs.tag_name }} | |
| run: | | |
| # Create version file for dynamic versioning | |
| echo "${{ env.VERSION_TAG }}" > core/version.txt | |
| # 1. Build Base Binary | |
| pyinstaller --name WASP --onefile --windowed --add-data "core:core" --add-data "gui:gui" --add-data "LICENSE:." --add-data "core/version.txt:core" --hidden-import "pynput.keyboard._xorg" --hidden-import "pynput.mouse._xorg" main.py | |
| # Rename binary | |
| cp dist/WASP "dist/WASP-${{ env.VERSION_TAG }}-linux" | |
| # Clean version for control file (remove v) | |
| CLEAN_VER="${VERSION_TAG#v}" | |
| # 2. Create .deb Package | |
| mkdir -p deb_pkg/usr/local/bin | |
| mkdir -p deb_pkg/DEBIAN | |
| cp dist/WASP deb_pkg/usr/local/bin/wasp-app | |
| chmod +x deb_pkg/usr/local/bin/wasp-app | |
| # Control File | |
| echo "Package: wasp-app" > deb_pkg/DEBIAN/control | |
| echo "Version: $CLEAN_VER" >> deb_pkg/DEBIAN/control | |
| echo "Architecture: amd64" >> deb_pkg/DEBIAN/control | |
| echo "Maintainer: GitHub Action" >> deb_pkg/DEBIAN/control | |
| echo "Description: WASP Application" >> deb_pkg/DEBIAN/control | |
| dpkg-deb --build deb_pkg "dist/WASP-${{ env.VERSION_TAG }}-linux.deb" | |
| # 3. Create AppImage | |
| # Prepare AppDir | |
| mkdir -p AppDir/usr/bin | |
| cp dist/WASP AppDir/usr/bin/wasp-app | |
| # Desktop File | |
| echo "[Desktop Entry]" > AppDir/wasp.desktop | |
| echo "Name=WASP" >> AppDir/wasp.desktop | |
| echo "Exec=wasp-app" >> AppDir/wasp.desktop | |
| echo "Icon=wasp" >> AppDir/wasp.desktop | |
| echo "Type=Application" >> AppDir/wasp.desktop | |
| echo "Categories=Utility;" >> AppDir/wasp.desktop | |
| # Icon | |
| if [ -f icon.ico ]; then convert icon.ico AppDir/wasp.png; else touch AppDir/wasp.png; fi | |
| # AppRun | |
| echo '#!/bin/sh' > AppDir/AppRun | |
| echo 'exec "$APPDIR/usr/bin/wasp-app" "$@"' >> AppDir/AppRun | |
| chmod +x AppDir/AppRun | |
| # AppImageTool | |
| wget -q https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage | |
| chmod +x appimagetool-x86_64.AppImage | |
| # Build AppImage | |
| ARCH=x86_64 ./appimagetool-x86_64.AppImage AppDir "dist/WASP-${{ env.VERSION_TAG }}-linux.AppImage" | |
| - name: Build with PyInstaller (macOS - App, Zip, DMG) | |
| if: runner.os == 'macOS' | |
| env: | |
| VERSION_TAG: ${{ needs.create_release.outputs.tag_name }} | |
| run: | | |
| # Create version file for dynamic versioning | |
| echo "${{ env.VERSION_TAG }}" > core/version.txt | |
| pyinstaller --name WASP --onefile --windowed --add-data "core:core" --add-data "gui:gui" --add-data "LICENSE:." --add-data "core/version.txt:core" main.py | |
| # 1. Zip the .app | |
| cd dist | |
| zip -r "WASP-${{ env.VERSION_TAG }}-macos.app.zip" WASP.app | |
| cd .. | |
| # 2. Create DMG | |
| hdiutil create dist/WASP.dmg -srcfolder dist/WASP.app -ov -format UDZO | |
| mv dist/WASP.dmg "dist/WASP-${{ env.VERSION_TAG }}-macos.dmg" | |
| - name: Move to Output Folder | |
| shell: bash | |
| env: | |
| VERSION_TAG: ${{ needs.create_release.outputs.tag_name }} | |
| run: | | |
| mkdir -p output | |
| if [ "${{ runner.os }}" == "Windows" ]; then | |
| cp "dist/WASP-${{ env.VERSION_TAG }}-windows.exe" output/ | |
| elif [ "${{ runner.os }}" == "Linux" ]; then | |
| cp "dist/WASP-${{ env.VERSION_TAG }}-linux.deb" output/ | |
| cp "dist/WASP-${{ env.VERSION_TAG }}-linux.AppImage" output/ | |
| elif [ "${{ runner.os }}" == "macOS" ]; then | |
| cp "dist/WASP-${{ env.VERSION_TAG }}-macos.dmg" output/ | |
| cp "dist/WASP-${{ env.VERSION_TAG }}-macos.app.zip" output/ | |
| fi | |
| - name: Upload Release Assets | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ needs.create_release.outputs.tag_name }} | |
| files: output/* | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Upload Artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: WASP-${{ matrix.os }} | |
| path: output/* |