Merge branch 'main' of https://github.com/Spec-DY/popup-window #13
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 Pyinstaller Client App | |
| on: | |
| push: | |
| branches: | |
| - main | |
| paths: | |
| - "client/**" | |
| - ".github/workflows/BuildApp.yaml" | |
| permissions: | |
| contents: write | |
| # build job | |
| jobs: | |
| build: | |
| runs-on: ${{ matrix.os }} | |
| name: Build Client App (${{ matrix.os }}) | |
| strategy: | |
| matrix: | |
| os: [windows-latest, ubuntu-latest] | |
| steps: | |
| - name: 🍗Checkout code | |
| uses: actions/checkout@v4 | |
| - name: 🍎Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - name: 🍟Install dependencies (Windows) | |
| if: matrix.os == 'windows-latest' | |
| run: | | |
| python -m pip install --upgrade pip | |
| if (Test-Path "client/requirements.txt") { pip install -r client/requirements.txt } | |
| pip install pyinstaller | |
| shell: pwsh | |
| - name: 🍟Install dependencies (Linux) | |
| if: matrix.os == 'ubuntu-latest' | |
| run: | | |
| python -m pip install --upgrade pip | |
| if [ -f client/requirements.txt ]; then pip install -r client/requirements.txt; fi | |
| pip install pyinstaller | |
| shell: bash | |
| - name: 🎨Create version file (Windows) | |
| if: matrix.os == 'windows-latest' | |
| run: | | |
| $versionContent = @" | |
| # UTF-8 | |
| VSVersionInfo( | |
| ffi=FixedFileInfo( | |
| mask=0x3f, | |
| flags=0x0, | |
| OS=0x40004, | |
| fileType=0x1, | |
| subtype=0x0, | |
| date=(0, 0) | |
| ), | |
| kids=[ | |
| StringFileInfo( | |
| [ | |
| StringTable( | |
| u'040904B0', | |
| [ | |
| StringStruct(u'CompanyName', u'Spec-DY'), | |
| StringStruct(u'FileDescription', u'Popup Window Like Malware'), | |
| StringStruct(u'InternalName', u'client'), | |
| StringStruct(u'LegalCopyright', u'Copyright (C) 2025 Spec-DY'), | |
| StringStruct(u'OriginalFilename', u'client.exe'), | |
| StringStruct(u'ProductName', u'Popups'), | |
| ] | |
| ) | |
| ] | |
| ), | |
| VarFileInfo([VarStruct(u'Translation', [1033, 1200])]) | |
| ] | |
| ) | |
| "@ | |
| New-Item -Path "client/util" -ItemType Directory -Force | |
| Set-Content -Path "client/util/version.txt" -Value $versionContent -Encoding UTF8 | |
| Write-Output "✅ Version file created at client/util/version.txt" | |
| shell: pwsh | |
| - name: 🌭Build the app (Windows) | |
| if: matrix.os == 'windows-latest' | |
| run: | | |
| pyinstaller --onefile --noconsole --version-file=client/util/version.txt --add-data "client/assets/appicon.ico;." --add-data "client/assets/appicon.jpg;." --icon client/assets/appicon.jpg client/client.py | |
| Write-Output "✅ Executable built successfully" | |
| shell: pwsh | |
| - name: 🔐Sign executable (Windows) | |
| if: matrix.os == 'windows-latest' | |
| run: | | |
| Write-Output "🔐 Creating self-signed certificate (2 years validity)..." | |
| $cert = New-SelfSignedCertificate -DnsName "Spec-DY" -Type CodeSigning -CertStoreLocation cert:\CurrentUser\My -NotAfter (Get-Date).AddYears(2) | |
| Write-Output "Certificate created: $($cert.Subject)" | |
| Write-Output "Certificate valid until: $($cert.NotAfter)" | |
| Write-Output "🔐 Signing executable..." | |
| Set-AuthenticodeSignature -FilePath "dist/client.exe" -Certificate $cert | |
| Write-Output "🔐 Verifying signature..." | |
| $signature = Get-AuthenticodeSignature -FilePath "dist/client.exe" | |
| Write-Output "Signature status: $($signature.Status)" | |
| Write-Output "Signer: $($signature.SignerCertificate.Subject)" | |
| Write-Output "Signature valid until: $($signature.SignerCertificate.NotAfter)" | |
| # Check if signature exists (even if not fully trusted) | |
| if ($signature.SignerCertificate -ne $null) { | |
| Write-Output "✅ File signed successfully with 2-year certificate (Status: $($signature.Status))" | |
| } else { | |
| Write-Output "❌ Signature verification failed" | |
| exit 1 | |
| } | |
| shell: pwsh | |
| - name: 🍬Build the app (Ubuntu) | |
| if: matrix.os == 'ubuntu-latest' | |
| run: | | |
| pyinstaller --onefile --add-data "client/assets/appicon.ico:." --add-data "client/assets/appicon.jpg:." client/client.py | |
| - name: 🍩Upload artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: client-${{ matrix.os }} | |
| path: ./dist/ | |
| retention-days: 7 | |
| # release job | |
| release: | |
| needs: build | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: 🍗Checkout code (for server.py) | |
| uses: actions/checkout@v4 | |
| - name: 🍭Generate timestamp version | |
| id: version | |
| run: | | |
| VERSION="v$(date +'%Y.%m.%d-%H%M%S')" | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| - name: 📥Download artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: ./artifacts | |
| - name: 📥Download existing release assets | |
| id: download_existing | |
| run: | | |
| echo "🔍 Checking for existing release..." | |
| LATEST_RELEASE=$(curl -s "https://api.github.com/repos/${{ github.repository }}/releases/latest" || echo "{}") | |
| # check current release | |
| if [ "$(echo $LATEST_RELEASE | jq -r '.message')" != "Not Found" ]; then | |
| echo "✅ Found existing release, downloading assets..." | |
| # create directory for existing assets | |
| mkdir -p ./existing-assets | |
| # download existing apk | |
| APK_URL=$(echo $LATEST_RELEASE | jq -r '.assets[] | select(.name | contains(".apk")) | .browser_download_url') | |
| if [ "$APK_URL" != "null" ] && [ -n "$APK_URL" ]; then | |
| echo "📱 Downloading existing APK..." | |
| curl -L -o "./existing-assets/$(basename $(echo $APK_URL))" "$APK_URL" | |
| fi | |
| # download existing files except client executables | |
| echo $LATEST_RELEASE | jq -r '.assets[] | select(.name | contains("server.py")) | .browser_download_url' | while read url; do | |
| if [ -n "$url" ]; then | |
| echo "📥 Downloading: $(basename $url)" | |
| curl -L -o "./existing-assets/$(basename $url)" "$url" | |
| fi | |
| done | |
| echo "existing_files=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "ℹ️ No existing release found" | |
| echo "existing_files=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: 🍩Rename and prepare files | |
| run: | | |
| mkdir -p ./release | |
| # copy current files | |
| if [ "${{ steps.download_existing.outputs.existing_files }}" == "true" ]; then | |
| cp -r ./existing-assets/* ./release/ 2>/dev/null || true | |
| fi | |
| # add new python file to release directory | |
| if [ -f ./artifacts/client-windows-latest/client.exe ]; then | |
| mv ./artifacts/client-windows-latest/client.exe ./release/client-${{ steps.version.outputs.version }}-windows.exe | |
| fi | |
| if [ -f ./artifacts/client-ubuntu-latest/client ]; then | |
| mv ./artifacts/client-ubuntu-latest/client ./release/client-${{ steps.version.outputs.version }}-ubuntu | |
| fi | |
| # add server.py file if it exists | |
| if [ -f ./server.py ]; then | |
| cp ./server.py ./release/server.py | |
| fi | |
| # clean up old files | |
| find ./release -name "client-v*-windows.exe" ! -name "client-${{ steps.version.outputs.version }}-windows.exe" -delete 2>/dev/null || true | |
| find ./release -name "client-v*-ubuntu" ! -name "client-${{ steps.version.outputs.version }}-ubuntu" -delete 2>/dev/null || true | |
| echo "=== Final release files ===" | |
| ls -la ./release/ | |
| - name: 🍆Create Release and Upload Assets | |
| uses: softprops/action-gh-release@v1 | |
| with: | |
| tag_name: ${{ steps.version.outputs.version }} | |
| name: Release ${{ steps.version.outputs.version }} | |
| body: | | |
| 🚀 **Multi-Platform Release** | |
| Automatically built and released from commit ${{ github.sha }} | |
| ## 📋 Server Setup | |
| 1. Clone repository and deploy `server.py` on your server | |
| 3. Run: `python3 server.py` | |
| 4. Server will listen on port 12345 by default | |
| ## 💻 Desktop Clients | |
| 1. Download the appropriate client for your OS | |
| 2. Run the executable | |
| 3. If server and client are on same device, use `127.0.0.1` as server address | |
| ## 📱 Mobile App (Android) | |
| 1. Download the APK file | |
| 2. Enable "Install from unknown sources" in Android settings | |
| 3. Install the APK on your device | |
| 4. Configure server address in the app | |
| ## 📦 Available Downloads | |
| - **Windows Desktop**: `client-${{ steps.version.outputs.version }}-windows.exe` | |
| - **Linux Desktop**: `client-${{ steps.version.outputs.version }}-ubuntu` | |
| - **Android Mobile**: `client-${{ steps.version.outputs.version }}-android.apk` | |
| - **Server**: Clone repository for `server.py` | |
| files: ./release/* | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |