name: native-build on: workflow_dispatch: inputs: tag: required: true description: "Ref to build from (e.g. v1.0.0)" useWorkflowSpec: type: boolean default: false description: "Use app.spec from workflow branch instead of tag" push: tags: - "v*" jobs: build: if: ${{ vars.REGISTRY == '' }} runs-on: ${{ matrix.os }} strategy: matrix: include: - os: ubuntu-latest arch: amd64 - os: ubuntu-latest arch: arm64 - os: macos-latest arch: arm64 - os: windows-latest arch: amd64 - os: windows-latest arch: arm64 permissions: packages: write contents: write env: PYTHON_VERSION: "3.13" BUN_VERSION: latest NODE_VERSION: 22 TAG_NAME: ${{ github.event.inputs.tag || github.ref_name }} steps: - name: Checkout source repo uses: actions/checkout@v4 with: ref: ${{ env.TAG_NAME }} - name: Overwrite app.spec from workflow branch if: ${{ github.event.inputs.useWorkflowSpec == 'true' }} uses: actions/checkout@v4 with: ref: ${{ github.ref }} sparse-checkout: | app.spec sparse-checkout-cone-mode: false path: temp-spec - name: Replace app.spec with version from workflow branch if: ${{ github.event.inputs.useWorkflowSpec == 'true' }} shell: bash run: cp temp-spec/app.spec ./app.spec - name: Update app/library/version.py shell: bash run: | VERSION="${TAG_NAME}" SHA=$(git rev-parse HEAD) DATE=$(date -u +"%Y%m%d") BRANCH=$(git branch --show-current) if [ -z "${BRANCH}" ]; then BRANCH="${TAG_NAME}" fi BRANCH=$(echo "${BRANCH}" | sed 's#/#-#g') echo "APP_VERSION=${VERSION}" >> "$GITHUB_ENV" echo "APP_SHA=${SHA}" >> "$GITHUB_ENV" echo "APP_DATE=${DATE}" >> "$GITHUB_ENV" echo "APP_BRANCH=${BRANCH}" >> "$GITHUB_ENV" sed -i.bak \ -e "s/^APP_VERSION = \".*\"/APP_VERSION = \"${VERSION}\"/" \ -e "s/^APP_COMMIT_SHA = \".*\"/APP_COMMIT_SHA = \"${SHA}\"/" \ -e "s/^APP_BUILD_DATE = \".*\"/APP_BUILD_DATE = \"${DATE}\"/" \ -e "s/^APP_BRANCH = \".*\"/APP_BRANCH = \"${BRANCH}\"/" \ app/library/version.py rm -f app/library/version.py.bak echo "Updated version info:" cat app/library/version.py - name: Cache Python venv id: cache-python uses: actions/cache@v4 with: path: .venv key: uv-${{ runner.os }}-${{ matrix.arch }}-${{ env.PYTHON_VERSION }}-${{ hashFiles('uv.lock') }} restore-keys: | uv-${{ runner.os }}-${{ matrix.arch }}-${{ env.PYTHON_VERSION }}- - name: Set up Python uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} architecture: "x64" - name: Install Python dependencies shell: bash run: | pip install uv if [ ! -d .venv ]; then uv venv --system-site-packages --relocatable fi uv sync --link-mode=copy --active --extra installer - name: Cache bun installation id: cache-bun uses: actions/cache@v4 with: path: ~/.bun/install/cache key: ${{ runner.os }}-${{ matrix.arch }}-bun-${{ hashFiles('**/bun.lock') }} restore-keys: | ${{ runner.os }}-${{ matrix.arch }}-bun- - name: Install bun uses: oven-sh/setup-bun@v2 with: bun-version: ${{ env.BUN_VERSION }} - name: Install Node.js uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} - name: Build frontend working-directory: ui shell: bash run: | bun install --production --prefer-offline --frozen-lockfile bun run generate - name: Clean build outputs (Unix) if: runner.os != 'Windows' shell: bash run: rm -rf build dist release || true - name: Clean build outputs (Windows) if: runner.os == 'Windows' shell: powershell run: | if (Test-Path build) { Remove-Item -Recurse -Force build } if (Test-Path dist) { Remove-Item -Recurse -Force dist } if (Test-Path release) { Remove-Item -Recurse -Force release } - name: Build native binary (Windows) if: matrix.os == 'windows-latest' shell: powershell run: | .\.venv\Scripts\activate uv run pyinstaller ./app.spec - name: Build native binary (Linux/macOS) if: matrix.os != 'windows-latest' shell: bash run: | . .venv/bin/activate uv run pyinstaller ./app.spec - name: Upload artifact uses: actions/upload-artifact@v4 with: name: app-${{ runner.os }}-${{ matrix.arch }}-${{ env.TAG_NAME }} path: dist/YTPTube/** - name: Package artifact (Unix) if: startsWith(env.TAG_NAME, 'v') && runner.os != 'Windows' shell: bash run: | mkdir -p release PKG_DIR="YTPTube-${{ env.TAG_NAME }}" ZIP_NAME="ytptube-${{ runner.os }}-${{ matrix.arch }}-${{ env.TAG_NAME }}.zip" if [ ! -f "dist/YTPTube/YTPTube" ]; then echo "Missing dist/YTPTube/YTPTube" find dist -maxdepth 3 -type f | head -n 200 exit 1 fi rm -rf "dist/${PKG_DIR}" mv "dist/YTPTube" "dist/${PKG_DIR}" zip -yr "release/${ZIP_NAME}" "dist/${PKG_DIR}" - name: Package artifact (Windows) if: startsWith(env.TAG_NAME, 'v') && runner.os == 'Windows' shell: powershell run: | $pkgDir = "YTPTube-${{ env.TAG_NAME }}" $zipName = "ytptube-${{ runner.os }}-${{ matrix.arch }}-${{ env.TAG_NAME }}.zip" New-Item -ItemType Directory -Force -Path release | Out-Null if (!(Test-Path "dist\YTPTube\YTPTube.exe")) { Write-Host "Missing dist\YTPTube\YTPTube.exe" Get-ChildItem -Recurse dist | Select-Object -First 200 | Format-Table -AutoSize exit 1 } if (Test-Path "dist\$pkgDir") { Remove-Item -Recurse -Force "dist\$pkgDir" } Move-Item "dist\YTPTube" "dist\$pkgDir" Compress-Archive -Path "dist\$pkgDir" -DestinationPath "release\$zipName" -Force - name: Upload to GitHub Release if: startsWith(env.TAG_NAME, 'v') uses: softprops/action-gh-release@v2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: tag_name: ${{ env.TAG_NAME }} files: release/*.zip