diff --git a/.github/workflows/simple-release.yml b/.github/workflows/simple-release.yml index bcd3ca2..b46473f 100644 --- a/.github/workflows/simple-release.yml +++ b/.github/workflows/simple-release.yml @@ -1,7 +1,25 @@ +# Multi-platform build + packaging workflow +# - Builds a pyinstaller executable on Windows, Debian, Arch, Rocky. +# - Packages using fpm into .deb, .rpm, and pacman (.pkg.tar.zst) files with explicit filenames. +# - Creates a GitHub Release with the produced artifacts. +# +# Notes: +# - Poetry is installed via snok/install-poetry@v1 in all jobs. +# - fpm gem is pinned to 1.16.0 in the examples; change as needed. +# - Rocky job uses tarball downloads for pyenv and python-build (non-interactive, CI-friendly). name: Build Multi-Platform Binaries on: - workflow_dispatch: # Manual trigger only + workflow_dispatch: + +permissions: + contents: write + +env: + # change this if you prefer a different pinned fpm version + FPM_VERSION: "1.16.0" + # Personal Access Token for HTTPS git operations (populate in repository secrets) + CI_CD_PAT: ${{ secrets.CI_CD_PAT }} jobs: build-windows: @@ -25,14 +43,9 @@ jobs: - name: Ensure Poetry is on PATH (Windows) shell: pwsh run: | - # Add the typical Poetry installer location to PATH for subsequent steps. - # This writes the directory to GITHUB_PATH so it is appended to PATH automatically. + # Add Poetry user bin to PATH for subsequent steps in this job $poetryPath = Join-Path $env:USERPROFILE ".local\bin" - Write-Output "Adding $poetryPath to PATH via GITHUB_PATH" Write-Output $poetryPath >> $Env:GITHUB_PATH - # Confirm it's on PATH for this step (diagnostics only) - Write-Output "PATH is now: $env:PATH" - Get-Command -ErrorAction SilentlyContinue poetry | ForEach-Object { Write-Output "poetry location: $($_.Source)" } || Write-Output "poetry not found yet (will be available in subsequent steps)" - name: Install dependencies run: | @@ -53,10 +66,13 @@ jobs: container: image: python:3.12-slim steps: - - name: Install system dependencies + - name: Install system dependencies & gem fpm run: | + set -euo pipefail apt-get update - apt-get install -y curl git build-essential + apt-get install -y --no-install-recommends curl git build-essential ruby ruby-dev gcc make zlib1g-dev ca-certificates + # install pinned fpm to the system gem dir (will be available under gem env's EXECUTABLE DIRECTORY or /usr/local/bin) + gem install --no-document -v "${FPM_VERSION}" fpm - name: Checkout code uses: actions/checkout@v4 @@ -67,134 +83,6 @@ jobs: python-version: '3.12' - name: Install Poetry - run: | - curl -sSL https://install.python-poetry.org | python - - echo 'export PATH="$HOME/.local/bin:$PATH"' >> $GITHUB_ENV - - - name: Configure Poetry - run: | - export PATH="$HOME/.local/bin:$PATH" - poetry config virtualenvs.create true - poetry config virtualenvs.in-project true - - - name: Install dependencies - run: | - export PATH="$HOME/.local/bin:$PATH" - poetry env use python3.12 || true - poetry install - - - name: Build Debian executable - run: | - export PATH="$HOME/.local/bin:$PATH" - poetry run pyinstaller --onefile --icon=icon_media/robot_files_256.png --name android-file-handler src/main.py - - - name: Upload Debian artifact - uses: actions/upload-artifact@v4 - with: - name: debian-binary - path: dist/android-file-handler - - build-arch: - runs-on: ubuntu-latest - container: - image: archlinux:latest - steps: - - name: Install system dependencies - run: | - pacman -Syu --noconfirm - pacman -S --noconfirm python python-pip curl git base-devel - - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up Python 3.12 - uses: actions/setup-python@v5 - with: - python-version: '3.12' - - - name: Install Poetry - run: | - curl -sSL https://install.python-poetry.org | python - - echo 'export PATH="$HOME/.local/bin:$PATH"' >> $GITHUB_ENV - - - name: Configure Poetry - run: | - export PATH="$HOME/.local/bin:$PATH" - poetry config virtualenvs.create true - poetry config virtualenvs.in-project true - - - name: Install dependencies - run: | - export PATH="$HOME/.local/bin:$PATH" - poetry install - - - name: Build Arch executable - run: | - export PATH="$HOME/.local/bin:$PATH" - poetry run pyinstaller --onefile --icon=icon_media/robot_files_256.png --name android-file-handler src/main.py - - - name: Upload Arch artifact - uses: actions/upload-artifact@v4 - with: - name: arch-binary - path: dist/android-file-handler - - build-rocky: - runs-on: ubuntu-latest - container: - image: rockylinux:9 - steps: - - name: Install system build dependencies for Python and pyenv (enable CRB for -devel packages) - run: | - # enable the CodeReady Builder (CRB) repository so -devel packages (like gdbm-devel) are available - dnf -y install dnf-plugins-core - dnf config-manager --set-enabled crb - - # Refresh metadata and install the packages required to build CPython from source - dnf -y update - dnf -y install git gcc make openssl-devel bzip2-devel libffi-devel zlib-devel xz-devel \ - readline-devel sqlite-devel tk-devel gdbm-devel libuuid-devel patch - - - name: Checkout code - uses: actions/checkout@v4 - - - name: Install pyenv and build Python 3.12.11 (native to Rocky) — idempotent - env: - PYENV_ROOT: ${{ github.workspace }}/.pyenv_temp - run: | - # Use $HOME/.pyenv for the pyenv installation (runtime only — this will NOT change your repo files) - export PYENV_ROOT="$HOME/.pyenv" - export PATH="$PYENV_ROOT/bin:$PATH" - - # Clone or update pyenv (idempotent) - if [ -d "$PYENV_ROOT/.git" ]; then - echo "pyenv already exists — updating" - cd "$PYENV_ROOT" - git fetch --all --prune - git reset --hard origin/master || true - cd - - else - echo "Cloning pyenv" - git clone https://github.com/pyenv/pyenv.git "$PYENV_ROOT" - fi - - # Persist pyenv environment for subsequent steps - echo "PYENV_ROOT=$PYENV_ROOT" >> $GITHUB_ENV - echo "PATH=$PYENV_ROOT/shims:$PYENV_ROOT/bin:$PATH" >> $GITHUB_ENV - - # Initialize pyenv for this step and ensure pyenv is usable immediately - export PATH="$PYENV_ROOT/bin:$PATH" - eval "$($PYENV_ROOT/bin/pyenv init -)" - - # Install the specified Python version if not already installed (-s = skip if present) - $PYENV_ROOT/bin/pyenv install -s 3.12.11 - $PYENV_ROOT/bin/pyenv global 3.12.11 - - # Verify installed python - python --version - pip --version - - - name: Install Poetry (use action; Poetry will use the pyenv-built python) uses: snok/install-poetry@v1 with: version: latest @@ -208,41 +96,247 @@ jobs: poetry config virtualenvs.create true poetry config virtualenvs.in-project true - - name: Install dependencies + - name: Install dependencies & build executable run: | export PATH="$HOME/.local/bin:$PATH" - # ensure poetry uses the pyenv python - poetry env use 3.12.11 || true + poetry env use python3.12 || true poetry install - - - name: Build Rocky executable - run: | - export PATH="$HOME/.local/bin:$PATH" poetry run pyinstaller --onefile --icon=icon_media/robot_files_256.png --name android-file-handler src/main.py - - name: Upload Rocky artifact + - name: Package .deb (fpm) + run: | + set -euo pipefail + export PATH="$HOME/.local/bin:$PATH" + VERSION="$(poetry version -s)" + mkdir -p dist + chmod +x dist/android-file-handler + # explicit filename into dist/ + fpm -s dir -t deb -n android-file-handler -v "$VERSION" --architecture amd64 --prefix /usr/local/bin -p "dist/android-file-handler_${VERSION}_amd64.deb" dist/android-file-handler + + - name: Upload Debian .deb uses: actions/upload-artifact@v4 with: - name: rocky-binary - path: dist/android-file-handler + name: debian-package + path: dist/android-file-handler_*.deb + build-arch: + runs-on: ubuntu-latest + container: + image: archlinux:latest + steps: + - name: Install system dependencies (Arch) and system Ruby + run: | + set -euo pipefail + pacman -Syu --noconfirm + pacman -S --noconfirm ruby base-devel curl git tar ca-certificates + # Install fpm system-wide and pin version so fpm will be in /usr/local/bin + gem install --no-document erb + gem install --no-document -v "${FPM_VERSION}" fpm --bindir /usr/local/bin + # persist system bindir to subsequent steps (usually already on PATH) + echo "/usr/local/bin" >> $GITHUB_PATH + + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + version: latest + virtualenvs-create: true + virtualenvs-in-project: true + + - name: Configure Poetry + run: | + echo 'export PATH="$HOME/.local/bin:$PATH"' >> $GITHUB_ENV + export PATH="$HOME/.local/bin:$PATH" + + - name: Install dependencies & build executable + run: | + export PATH="$HOME/.local/bin:/usr/local/bin:$PATH" + poetry install + poetry run pyinstaller --onefile --icon=icon_media/robot_files_256.png --name android-file-handler src/main.py + + - name: Package pacman (fpm) + run: | + set -euo pipefail + export PATH="$HOME/.local/bin:/usr/local/bin:$PATH" + VERSION="$(poetry version -s)" + mkdir -p dist + chmod +x dist/android-file-handler + # explicit filename into dist/ + fpm -s dir -t pacman -n android-file-handler -v "$VERSION" --architecture x86_64 --prefix /usr/local/bin -p "dist/android-file-handler-${VERSION}-1-x86_64.pkg.tar.zst" dist/android-file-handler + + - name: Upload Arch package + uses: actions/upload-artifact@v4 + with: + name: arch-package + path: dist/*.pkg.tar.* + + + create-release: - needs: [build-windows, build-debian, build-arch, build-rocky] + needs: [build-windows, build-debian, build-arch] runs-on: ubuntu-latest steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install Poetry + uses: snok/install-poetry@v1 + + - name: Get version + id: version + run: echo "version=$(poetry version -s)" >> $GITHUB_OUTPUT + - name: Download all artifacts uses: actions/download-artifact@v4 with: merge-multiple: true path: ./binaries + - name: List downloaded binaries (debug) + run: | + echo "Downloaded files:" + ls -la ./binaries || true - name: Create Release uses: softprops/action-gh-release@v1 with: + tag_name: v${{ steps.version.outputs.version }} + name: Release v${{ steps.version.outputs.version }} files: | ./binaries/android-file-handler.exe - ./binaries/android-file-handler + ./binaries/android-file-handler_*.deb + ./binaries/android-file-handler-*.rpm + ./binaries/android-file-handler-*-x86_64.pkg.tar.* draft: false prerelease: false env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + # build-rocky: + # runs-on: ubuntu-latest + # container: + # image: rockylinux:9 + # steps: + # - name: Robust dnf setup and install build deps (retry-clean-refresh) + # run: | + # set -euo pipefail + # retry() { + # local max_tries=5 + # local sleep_base=3 + # local n=1 + # until "$@"; do + # if [ $n -ge $max_tries ]; then + # echo "Command failed after $n attempts: $*" + # return 1 + # fi + # echo "Command failed: $*. Retrying ($n/$max_tries) after $((sleep_base * n))s..." + # sleep $((sleep_base * n)) + # n=$((n + 1)) + # done + # return 0 + # } + + # # Ensure plugin and enable CRB + # retry dnf -y install dnf-plugins-core + # retry dnf config-manager --set-enabled crb || true + + # # Clean caches and refresh metadata + # retry dnf -y clean all + # rm -rf /var/cache/dnf || true + # retry dnf -y makecache --refresh + + # # Install build-time deps including ruby so gem stdlib is present + # retry dnf -y install -y \ + # git gcc make openssl-devel bzip2-devel libffi-devel zlib-devel xz-devel \ + # readline-devel sqlite-devel tk-devel gdbm-devel libuuid-devel patch \ + # ruby ruby-devel rubygems rpm-build tar ca-certificates wget + + # - name: Clean up pyenv + # run: | + # echo "Removing existing pyenv installations" + # rm -rf "${GITHUB_WORKSPACE}/.pyenv" + # rm -rf "${HOME}/.pyenv" + + # - name: Tarball-based pyenv + python-build (non-interactive) + # env: + # PYENV_ROOT: ${{ github.workspace }}/.pyenv # Set this BEFORE running installer + # run: | + # set -euo pipefail + + # echo "PYENV_ROOT is set to: $PYENV_ROOT" + # mkdir -p "$PYENV_ROOT" + + # echo "Downloading pyenv installer and running it" + # wget -qO- https://pyenv.run | bash + + # # Initialize pyenv environment for this job + # export PATH="$PYENV_ROOT/bin:$PATH" + # eval "$($PYENV_ROOT/bin/pyenv init -)" + + # # Persist environment variables for subsequent steps + # echo "PYENV_ROOT=$PYENV_ROOT" >> $GITHUB_ENV + # echo "PATH=$PYENV_ROOT/shims:$PYENV_ROOT/bin:$PATH" >> $GITHUB_ENV + + # echo "pyenv version:" + # "$PYENV_ROOT/bin/pyenv" --version || true + + # - name: Build Python with pyenv (3.12.11) and set global + # env: + # PYENV_ROOT: ${{ github.workspace }}/.pyenv + # run: | + # set -euo pipefail + # export PYENV_ROOT="${PYENV_ROOT}" + # export PATH="$PYENV_ROOT/bin:$PATH" + # eval "$($PYENV_ROOT/bin/pyenv init -)" + # # Install python (idempotent) + # $PYENV_ROOT/bin/pyenv install -s 3.12.11 + # $PYENV_ROOT/bin/pyenv global 3.12.11 + # python --version + # pip --version + + # - name: Install Poetry + # uses: snok/install-poetry@v1 + # with: + # version: latest + # virtualenvs-create: true + # virtualenvs-in-project: true + + # - name: Configure Poetry + # run: | + # echo 'export PATH="$HOME/.local/bin:$PATH"' >> $GITHUB_ENV + # export PATH="$HOME/.local/bin:$PATH" + # poetry config virtualenvs.create true + # poetry config virtualenvs.in-project true + + # - name: Install dependencies & build executable + # run: | + # set -euo pipefail + # export PATH="$HOME/.local/bin:$PYENV_ROOT/shims:$PYENV_ROOT/bin:$PATH" + # poetry env use 3.12.11 || true + # poetry install + # poetry run pyinstaller --onefile --icon=icon_media/robot_files_256.png --name android-file-handler src/main.py + + # - name: Install fpm and package .rpm + # run: | + # set -euo pipefail + # # install pinned fpm and ensure binary is in system bindir + # gem install --no-document -v "${FPM_VERSION}" fpm --bindir /usr/local/bin + # echo "/usr/local/bin" >> $GITHUB_PATH + + # # Build rpm with explicit filename + # VERSION="$(poetry version -s)" + # mkdir -p dist + # chmod +x dist/android-file-handler + # fpm -s dir -t rpm -n android-file-handler -v "$VERSION" --architecture x86_64 --prefix /usr/local/bin -p "dist/android-file-handler-${VERSION}-1.x86_64.rpm" dist/android-file-handler + + # - name: Upload Rocky RPM + # uses: actions/upload-artifact@v4 + # with: + # name: rocky-package + # path: dist/*.rpm