From b11b5baa9f5044dc3cf38ad39e0d539860b26ce9 Mon Sep 17 00:00:00 2001 From: Suyog Tandel Date: Mon, 20 Jul 2026 21:04:02 +0530 Subject: [PATCH] ci/cd: new improved appimage builds for picoforge release workflow --- .../containers/Containerfile.glibc-aarch64 | 46 +++++++++++ .github/containers/Containerfile.glibc-x86_64 | 46 +++++++++++ .github/containers/Containerfile.musl-aarch64 | 36 ++++++++ .github/containers/Containerfile.musl-x86_64 | 36 ++++++++ .github/scripts/build_appimage.sh | 82 ++++++++++++++----- .github/workflows/publish-containers.yml | 58 +++++++++++++ .github/workflows/release.yml | 41 ++++++++-- 7 files changed, 315 insertions(+), 30 deletions(-) create mode 100644 .github/containers/Containerfile.glibc-aarch64 create mode 100644 .github/containers/Containerfile.glibc-x86_64 create mode 100644 .github/containers/Containerfile.musl-aarch64 create mode 100644 .github/containers/Containerfile.musl-x86_64 create mode 100644 .github/workflows/publish-containers.yml diff --git a/.github/containers/Containerfile.glibc-aarch64 b/.github/containers/Containerfile.glibc-aarch64 new file mode 100644 index 0000000..7b1ea04 --- /dev/null +++ b/.github/containers/Containerfile.glibc-aarch64 @@ -0,0 +1,46 @@ +FROM rockylinux:8 + +# Install EPEL, enable powertools, and install build dependencies +RUN dnf install -y epel-release dnf-plugins-core && \ + dnf config-manager --set-enabled powertools && \ + dnf install -y \ + gcc-toolset-15-gcc \ + gcc-toolset-15-gcc-c++ \ + gcc-toolset-15-binutils \ + make \ + pkgconf-pkg-config \ + curl \ + git \ + file \ + wget \ + patchelf \ + desktop-file-utils \ + fontconfig-devel \ + freetype-devel \ + libxcb-devel \ + libxkbcommon-devel \ + libxkbcommon-x11-devel \ + pcsc-lite-devel \ + systemd-devel \ + vulkan-headers \ + libX11-devel && \ + dnf clean all + +# Environment setup for GCC Toolset 15 and Rust +ENV RUSTUP_HOME=/usr/local/rustup \ + CARGO_HOME=/usr/local/cargo \ + PATH=/usr/local/cargo/bin:/opt/rh/gcc-toolset-15/root/usr/bin:$PATH + +# Install Rust stable toolchain +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable && \ + rustc --version && cargo --version + +# Install pre-extracted linuxdeploy for aarch64 +RUN wget -q https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-aarch64.AppImage -O /tmp/linuxdeploy.AppImage && \ + chmod +x /tmp/linuxdeploy.AppImage && \ + cd /tmp && /tmp/linuxdeploy.AppImage --appimage-extract && \ + mv /tmp/squashfs-root /usr/local/share/linuxdeploy && \ + ln -s /usr/local/share/linuxdeploy/AppRun /usr/local/bin/linuxdeploy && \ + rm /tmp/linuxdeploy.AppImage + +WORKDIR /workspace diff --git a/.github/containers/Containerfile.glibc-x86_64 b/.github/containers/Containerfile.glibc-x86_64 new file mode 100644 index 0000000..bfb40d0 --- /dev/null +++ b/.github/containers/Containerfile.glibc-x86_64 @@ -0,0 +1,46 @@ +FROM rockylinux:8 + +# Install EPEL, enable powertools, and install build dependencies +RUN dnf install -y epel-release dnf-plugins-core && \ + dnf config-manager --set-enabled powertools && \ + dnf install -y \ + gcc-toolset-15-gcc \ + gcc-toolset-15-gcc-c++ \ + gcc-toolset-15-binutils \ + make \ + pkgconf-pkg-config \ + curl \ + git \ + file \ + wget \ + patchelf \ + desktop-file-utils \ + fontconfig-devel \ + freetype-devel \ + libxcb-devel \ + libxkbcommon-devel \ + libxkbcommon-x11-devel \ + pcsc-lite-devel \ + systemd-devel \ + vulkan-headers \ + libX11-devel && \ + dnf clean all + +# Environment setup for GCC Toolset 15 and Rust +ENV RUSTUP_HOME=/usr/local/rustup \ + CARGO_HOME=/usr/local/cargo \ + PATH=/usr/local/cargo/bin:/opt/rh/gcc-toolset-15/root/usr/bin:$PATH + +# Install Rust stable toolchain +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable && \ + rustc --version && cargo --version + +# Install pre-extracted linuxdeploy +RUN wget -q https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage -O /tmp/linuxdeploy.AppImage && \ + chmod +x /tmp/linuxdeploy.AppImage && \ + cd /tmp && /tmp/linuxdeploy.AppImage --appimage-extract && \ + mv /tmp/squashfs-root /usr/local/share/linuxdeploy && \ + ln -s /usr/local/share/linuxdeploy/AppRun /usr/local/bin/linuxdeploy && \ + rm /tmp/linuxdeploy.AppImage + +WORKDIR /workspace diff --git a/.github/containers/Containerfile.musl-aarch64 b/.github/containers/Containerfile.musl-aarch64 new file mode 100644 index 0000000..a0fa54d --- /dev/null +++ b/.github/containers/Containerfile.musl-aarch64 @@ -0,0 +1,36 @@ +FROM alpine:latest + +# Install build dependencies, linux-headers, and libraries +RUN apk add --no-cache \ + build-base \ + linux-headers \ + pkgconf \ + curl \ + git \ + file \ + wget \ + patchelf \ + bash \ + gcompat \ + desktop-file-utils \ + fontconfig-dev \ + freetype-dev \ + libxcb-dev \ + libxkbcommon-dev \ + pcsc-lite-dev \ + eudev-dev \ + vulkan-headers \ + rust \ + cargo + +# Install pre-extracted linuxdeploy for aarch64 (runs via gcompat) +RUN wget -q https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-aarch64.AppImage -O /tmp/linuxdeploy.AppImage && \ + chmod +x /tmp/linuxdeploy.AppImage && \ + cd /tmp && /tmp/linuxdeploy.AppImage --appimage-extract && \ + mv /tmp/squashfs-root /usr/local/share/linuxdeploy && \ + ln -s /usr/local/share/linuxdeploy/AppRun /usr/local/bin/linuxdeploy && \ + rm -f /usr/local/share/linuxdeploy/usr/bin/strip && \ + ln -s /usr/bin/strip /usr/local/share/linuxdeploy/usr/bin/strip && \ + rm /tmp/linuxdeploy.AppImage + +WORKDIR /workspace diff --git a/.github/containers/Containerfile.musl-x86_64 b/.github/containers/Containerfile.musl-x86_64 new file mode 100644 index 0000000..0460c13 --- /dev/null +++ b/.github/containers/Containerfile.musl-x86_64 @@ -0,0 +1,36 @@ +FROM alpine:latest + +# Install build dependencies, linux-headers, and libraries +RUN apk add --no-cache \ + build-base \ + linux-headers \ + pkgconf \ + curl \ + git \ + file \ + wget \ + patchelf \ + bash \ + gcompat \ + desktop-file-utils \ + fontconfig-dev \ + freetype-dev \ + libxcb-dev \ + libxkbcommon-dev \ + pcsc-lite-dev \ + eudev-dev \ + vulkan-headers \ + rust \ + cargo + +# Install pre-extracted linuxdeploy (runs via gcompat) +RUN wget -q https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage -O /tmp/linuxdeploy.AppImage && \ + chmod +x /tmp/linuxdeploy.AppImage && \ + cd /tmp && /tmp/linuxdeploy.AppImage --appimage-extract && \ + mv /tmp/squashfs-root /usr/local/share/linuxdeploy && \ + ln -s /usr/local/share/linuxdeploy/AppRun /usr/local/bin/linuxdeploy && \ + rm -f /usr/local/share/linuxdeploy/usr/bin/strip && \ + ln -s /usr/bin/strip /usr/local/share/linuxdeploy/usr/bin/strip && \ + rm /tmp/linuxdeploy.AppImage + +WORKDIR /workspace diff --git a/.github/scripts/build_appimage.sh b/.github/scripts/build_appimage.sh index 57c9e61..77c1408 100644 --- a/.github/scripts/build_appimage.sh +++ b/.github/scripts/build_appimage.sh @@ -1,27 +1,54 @@ #!/bin/bash -set -e +set -eo pipefail -VERSION=${version:-"0.0.0"} +VARIANT=${1:-"glibc-x86_64"} -ARCH=$(uname -m) -if [ "$ARCH" == "x86_64" ]; then - LINUXDEPLOY_ARCH="x86_64" - APPIMAGE_ARCH="x86-64" -elif [ "$ARCH" == "aarch64" ]; then - LINUXDEPLOY_ARCH="aarch64" - APPIMAGE_ARCH="arm64" +echo "=== Building PicoForge AppImage for variant: ${VARIANT} ===" + +# Locate PicoForge source directory +if [ -f "/workspace/Cargo.toml" ]; then + SRC_DIR="/workspace" +elif [ -f "/workspace/picoforge/Cargo.toml" ]; then + SRC_DIR="/workspace/picoforge" else - echo "Unsupported architecture: $ARCH" + echo "Error: Cargo.toml not found in /workspace or /workspace/picoforge" exit 1 fi -echo "Building AppImage for architecture: $ARCH" +cd "$SRC_DIR" -echo "Downloading linuxdeploy..." -wget "https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-${LINUXDEPLOY_ARCH}.AppImage" -chmod +x linuxdeploy-${LINUXDEPLOY_ARCH}.AppImage +# Extract version from Cargo.toml +VERSION=$(grep -m 1 '^version' Cargo.toml | sed -E 's/.*"([0-9]+\.[0-9]+\.[0-9]+)".*/\1/') +if [ -z "$VERSION" ]; then + VERSION="0.0.0" +fi +echo "PicoForge Version: ${VERSION}" -export APPIMAGE_EXTRACT_AND_RUN=1 +# Determine architecture and target naming +ARCH=$(uname -m) +if [ "$ARCH" == "x86_64" ]; then + ARCH_NAME="x86-64" +elif [ "$ARCH" == "aarch64" ]; then + ARCH_NAME="aarch64" +else + ARCH_NAME="$ARCH" +fi + +# Define output filename based on variant +case "$VARIANT" in + glibc-2.28-x86_64|glibc-2.28-aarch64) + OUTPUT_NAME="picoforge_${VERSION}_glibc-2.28_${ARCH_NAME}.AppImage" + ;; + musl-x86_64|musl-aarch64) + OUTPUT_NAME="picoforge_${VERSION}_musl_${ARCH_NAME}.AppImage" + ;; + *) + OUTPUT_NAME="picoforge_${VERSION}_${VARIANT}_${ARCH_NAME}.AppImage" + ;; +esac + +echo "Building release binary with Cargo..." +cargo build --release BINARY_PATH="target/release/picoforge" DESKTOP_FILE="data/in.suyogtandel.picoforge.desktop" @@ -42,8 +69,12 @@ if [ ! -f "$ICON_FILE" ]; then exit 1 fi -echo "Running linuxdeploy..." -./linuxdeploy-${LINUXDEPLOY_ARCH}.AppImage \ +echo "Packaging AppImage using linuxdeploy..." +export APPIMAGE_EXTRACT_AND_RUN=1 + +# Run linuxdeploy to bundle executable, desktop entry, icon, excluding host daemon libpcsclite +rm -rf AppDir +linuxdeploy \ --appdir AppDir \ --executable "$BINARY_PATH" \ --desktop-file "$DESKTOP_FILE" \ @@ -51,10 +82,17 @@ echo "Running linuxdeploy..." --exclude-library libpcsclite.so.1 \ --output appimage -rm "linuxdeploy-${LINUXDEPLOY_ARCH}.AppImage" +# Find generated AppImage file and rename to standard naming +GENERATED_APPIMAGE=$(ls -t *.AppImage 2>/dev/null | head -n 1) -mkdir -p target/release -mv *.AppImage "target/release/picoforge_${VERSION}_${APPIMAGE_ARCH}.AppImage" +if [ -z "$GENERATED_APPIMAGE" ]; then + echo "Error: AppImage generation failed" + exit 1 +fi -echo "AppImage build complete. Artifacts moved to target/release/" -ls -l target/release/*.AppImage +mkdir -p /workspace/target/release +mv "$GENERATED_APPIMAGE" "/workspace/target/release/${OUTPUT_NAME}" +rm -rf AppDir + +echo "=== Build Complete! Output: /workspace/target/release/${OUTPUT_NAME} ===" +ls -lh "/workspace/target/release/${OUTPUT_NAME}" diff --git a/.github/workflows/publish-containers.yml b/.github/workflows/publish-containers.yml new file mode 100644 index 0000000..44c1b2b --- /dev/null +++ b/.github/workflows/publish-containers.yml @@ -0,0 +1,58 @@ +name: Publish Builder Containers to GHCR + +on: + push: + branches: [ main, master ] + paths: + - 'Containerfile.*' + - '.github/workflows/publish-containers.yml' + workflow_dispatch: + +permissions: + contents: read + packages: write + +jobs: + publish-container: + name: Build & Push ${{ matrix.variant }} + strategy: + fail-fast: false + matrix: + include: + - variant: glibc-2.28-x86_64 + runner: ubuntu-latest + containerfile: Containerfile.glibc-x86_64 + - variant: glibc-2.28-aarch64 + runner: ubuntu-24.04-arm + containerfile: Containerfile.glibc-aarch64 + - variant: musl-x86_64 + runner: ubuntu-latest + containerfile: Containerfile.musl-x86_64 + - variant: musl-aarch64 + runner: ubuntu-24.04-arm + containerfile: Containerfile.musl-aarch64 + + runs-on: ${{ matrix.runner }} + + steps: + - name: Checkout repository + uses: actions/checkout@v7 + + - name: Log in to GHCR + uses: redhat-actions/podman-login@v1 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build Podman Container Image + run: | + IMAGE_TAG="ghcr.io/${{ github.repository_owner }}/picoforge-appimage-builder:${{ matrix.variant }}" + podman build -t "$IMAGE_TAG" -f .github/containers/${{ matrix.containerfile }} . + + - name: Push Container Image to GHCR + uses: redhat-actions/push-to-registry@v2 + with: + image: picoforge-appimage-builder + tags: ${{ matrix.variant }} + registry: ghcr.io/${{ github.repository_owner }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f568dad..7be0fc2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,12 +19,15 @@ jobs: fail-fast: false matrix: include: + # MacOS Builds: - platform: "macos-latest" args: "--target aarch64-apple-darwin" build_type: "standard" - platform: "macos-latest" args: "--target x86_64-apple-darwin" build_type: "standard" + + # Linux Builds: - platform: "ubuntu-22.04" args: "" build_type: "standard" @@ -37,6 +40,20 @@ jobs: - platform: "ubuntu-24.04-arm" args: "" build_type: "flatpak" + - platform: "ubuntu-latest" + appimage_variant: "glibc-2.28-x86_64" + build_type: "appimage" + - platform: "ubuntu-latest" + appimage_variant: "musl-x86_64" + build_type: "appimage" + - platform: "ubuntu-24.04-arm" + appimage_variant: "glibc-2.28-aarch64" + build_type: "appimage" + - platform: "ubuntu-24.04-arm" + appimage_variant: "musl-aarch64" + build_type: "appimage" + + # Windows Builds: - platform: "windows-latest" args: "--target x86_64-pc-windows-msvc" build_type: "standard" @@ -53,7 +70,7 @@ jobs: with: fetch-depth: 0 - - name: install Rust stable + - name: Install Rust stable if: matrix.build_type == 'standard' uses: dtolnay/rust-toolchain@stable with: @@ -67,7 +84,7 @@ jobs: with: key: ${{ matrix.platform }}-${{ matrix.args }} - - name: install dependencies (ubuntu only) + - name: Install dependencies (ubuntu only) if: matrix.platform == 'ubuntu-22.04' || matrix.platform == 'ubuntu-24.04-arm' run: | sudo apt-get update @@ -93,7 +110,7 @@ jobs: libxcb-shape0-dev \ libxcb-xfixes0-dev libusb-1.0-0-dev podman patchelf librsvg2-dev libappindicator3-dev libwebkit2gtk-4.1-dev - - name: install dependencies (ubuntu-arm64 only) + - name: Install dependencies (ubuntu-arm64 only) if: matrix.platform == 'ubuntu-24.04-arm' run: | sudo apt-get install xdg-utils @@ -107,7 +124,7 @@ jobs: echo "Version found: $version" echo "version=$version" >> $GITHUB_ENV - - name: install cargo-packager + - name: Install cargo-packager if: matrix.build_type == 'standard' uses: taiki-e/install-action@v2 with: @@ -125,11 +142,19 @@ jobs: if: (matrix.platform == 'ubuntu-22.04' || matrix.platform == 'ubuntu-24.04-arm') && matrix.build_type == 'standard' run: cargo packager --release --formats deb,pacman - - name: Build AppImage - if: (matrix.platform == 'ubuntu-22.04' || matrix.platform == 'ubuntu-24.04-arm') && matrix.build_type == 'standard' + - name: Build AppImage (via Container) + if: matrix.build_type == 'appimage' run: | - chmod +x .github/scripts/build_appimage.sh - ./.github/scripts/build_appimage.sh + IMAGE_NAME="ghcr.io/${{ github.repository_owner }}/picoforge-appimage-builder:${{ matrix.appimage_variant }}" + echo "Pulling container: ${IMAGE_NAME}" + podman pull "${IMAGE_NAME}" + + mkdir -p target/release + echo "Running build inside container..." + podman run --rm \ + -v "${{ github.workspace }}":/workspace:z \ + "${IMAGE_NAME}" \ + /workspace/.github/scripts/build_appimage.sh ${{ matrix.appimage_variant }} - name: Build Flatpak if: matrix.build_type == 'flatpak'