🏗️ Build and Test JellyTau / Run Tests (push) Successful in 15m52s
🏗️ Build and Test JellyTau / Supply Chain (push) Failing after 29s
Publish Documentation / Build & publish docs to gitea-pages (push) Successful in 5m35s
Traceability Validation / Check Requirement Traces (push) Successful in 11s
Build & Release / Run Tests (push) Successful in 14m53s
🏗️ Build and Test JellyTau / Android Compile Check (push) Successful in 4m22s
Build & Release / Build Linux (push) Successful in 20m53s
Build & Release / Build Windows (push) Successful in 15m41s
Build & Release / Build Android (push) Successful in 30m46s
Build & Release / Create Release (push) Successful in 38s
The v0.10.0 release build failed in Build Linux after 16 minutes: failed to bundle project: xdg-open binary not found /usr/bin/xdg-open: No such file or directory linuxdeploy embeds xdg-open into the AppImage and aborts the whole bundle when it is absent. deb and rpm had already bundled fine; only AppImage was affected. This is the one failure tonight that building locally could not have caught, and the reason is worth writing down: a developer machine is a desktop and always has xdg-utils, so the AppImage builds there and fails on a minimal server image. The asymmetry is the bug. Every other release defect this evening was found by building locally first; this one needed the runner. xdg-utils, desktop-file-utils and zsync are added together rather than one at a time. Each round trip costs an image rebuild plus a failed release build, and those three are what linuxdeploy commonly reaches for (xdg-open, desktop-file-validate, and zsync for delta updates). Workflows move to jellytau-builder:2026.08.1, built and pushed with all three verified present inside it before this commit. ci-operations.md gains two things learned here: that an apt addition invalidates the layer above the cargo-install steps, so it is a ~20 minute rebuild rather than the ~2 minutes the trailing layer normally gives; and that Tauri's AppImage bundler downloads linuxdeploy, AppRun and two plugin scripts from GitHub during the build, so an AppImage build depends on GitHub being reachable from the runner.
192 lines
8.4 KiB
Docker
192 lines
8.4 KiB
Docker
# JellyTau Builder Image
|
|
# Pre-built image with all dependencies for building, testing, and packaging:
|
|
# - Android APK (SDK/NDK), Linux desktop (deb/rpm),
|
|
# - Windows cross via the official Tauri path: MSVC target + cargo-xwin + NSIS
|
|
# Arch packages build in a separate archlinux image (Dockerfile.arch) since
|
|
# makepkg is Arch-specific.
|
|
# Push to your registry: docker build -f Dockerfile.builder -t gitea.tourolle.paris/dtourolle/jellytau-builder:latest .
|
|
|
|
FROM ubuntu:24.04
|
|
|
|
ENV DEBIAN_FRONTEND=noninteractive \
|
|
ANDROID_HOME=/opt/android-sdk \
|
|
NDK_VERSION=27.0.11902837 \
|
|
SDK_VERSION=36 \
|
|
BUILD_TOOLS_VERSION=35.0.0 \
|
|
RUST_BACKTRACE=1 \
|
|
PATH="/root/.bun/bin:/root/.cargo/bin:$PATH" \
|
|
CARGO_HOME=/root/.cargo
|
|
|
|
# Install system dependencies
|
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
build-essential \
|
|
curl \
|
|
wget \
|
|
git \
|
|
ca-certificates \
|
|
unzip \
|
|
jq \
|
|
openjdk-17-jdk-headless \
|
|
pkg-config \
|
|
libssl-dev \
|
|
libclang-dev \
|
|
llvm-dev \
|
|
# Tauri Linux desktop dependencies (needed for `cargo test` on the host target)
|
|
libglib2.0-dev \
|
|
libgtk-3-dev \
|
|
libwebkit2gtk-4.1-dev \
|
|
libjavascriptcoregtk-4.1-dev \
|
|
libsoup-3.0-dev \
|
|
librsvg2-dev \
|
|
libayatana-appindicator3-dev \
|
|
# mpv player library (linked via libmpv-sys)
|
|
libmpv-dev \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
# Install Node.js 20.x from NodeSource
|
|
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \
|
|
apt-get install -y --no-install-recommends nodejs && \
|
|
rm -rf /var/lib/apt/lists/*
|
|
|
|
# Install Bun
|
|
RUN curl -fsSL https://bun.sh/install | bash && \
|
|
ln -s /root/.bun/bin/bun /usr/local/bin/bun
|
|
|
|
# Install Rust using rustup, pinned to an exact release.
|
|
#
|
|
# 🔴 RUST_VERSION must equal `channel` in src-tauri/rust-toolchain.toml.
|
|
#
|
|
# The two are a pair. rust-toolchain.toml is what makes a developer's `cargo
|
|
# clippy` agree with CI's; this line is what makes the image already contain that
|
|
# toolchain. If they drift, rustup silently downloads the pinned version the
|
|
# first time cargo runs inside a job — a toolchain install at job time, which
|
|
# CLAUDE.md's "🔴 CI installs no system tools" rule forbids (and which costs
|
|
# ~1min plus a network dependency on every build).
|
|
#
|
|
# 🔴 Changing this line does NOT change CI on its own: the image must be
|
|
# rebuilt and pushed (`scripts/build-builder-image.sh`) before the new pin is
|
|
# authoritative. Bump rust-toolchain.toml and this line together, rebuild, push,
|
|
# then merge.
|
|
#
|
|
# Was: `sh -s -- -y` (latest stable, whatever it happened to be on rebuild day).
|
|
ENV RUST_VERSION=1.97.1
|
|
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | \
|
|
sh -s -- -y --profile minimal --default-toolchain "$RUST_VERSION" && \
|
|
. $HOME/.cargo/env && \
|
|
rustup default "$RUST_VERSION" && \
|
|
rustup target add aarch64-linux-android && \
|
|
rustup target add armv7-linux-androideabi && \
|
|
rustup target add x86_64-linux-android && \
|
|
rustup component add rustfmt clippy && \
|
|
rustc --version && \
|
|
cargo clippy --version
|
|
|
|
# Setup Android SDK
|
|
RUN mkdir -p $ANDROID_HOME && \
|
|
mkdir -p /root/.android && \
|
|
echo '### User Sources for `android` cmd line tool ###' > /root/.android/repositories.cfg && \
|
|
echo 'count=0' >> /root/.android/repositories.cfg
|
|
|
|
# Download and setup Android Command Line Tools
|
|
RUN wget -q https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip -O /tmp/cmdline-tools.zip && \
|
|
unzip -q /tmp/cmdline-tools.zip -d $ANDROID_HOME && \
|
|
rm /tmp/cmdline-tools.zip && \
|
|
mkdir -p $ANDROID_HOME/cmdline-tools/latest && \
|
|
mv $ANDROID_HOME/cmdline-tools/* $ANDROID_HOME/cmdline-tools/latest/ 2>/dev/null || true
|
|
|
|
# Accept all SDK licenses up front so Gradle can install/use components non-interactively
|
|
RUN yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --sdk_root=$ANDROID_HOME --licenses > /dev/null
|
|
|
|
# Install Android SDK components (must match the compileSdk/targetSdk in the generated Gradle project)
|
|
RUN $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --sdk_root=$ANDROID_HOME \
|
|
"platform-tools" \
|
|
"platforms;android-$SDK_VERSION" \
|
|
"build-tools;$BUILD_TOOLS_VERSION" \
|
|
"ndk;$NDK_VERSION" \
|
|
--channel=0 2>&1 | grep -v "Warning" || true
|
|
|
|
# Set NDK environment variable
|
|
ENV NDK_HOME=$ANDROID_HOME/ndk/$NDK_VERSION
|
|
|
|
# Gradle distribution. `tauri android init` regenerates gen/android with a
|
|
# wrapper pointing at services.gradle.org, so every Android job would otherwise
|
|
# download ~130MB of Gradle at build time — slow, and a hard failure when the
|
|
# CDN hiccups ("Unexpected end of file from server"). Ship the distribution in
|
|
# the image instead; scripts/sync-android-sources.sh repoints the regenerated
|
|
# wrapper at this local copy. Keep GRADLE_VERSION in sync with the version
|
|
# Tauri's generated wrapper requests.
|
|
ENV GRADLE_VERSION=8.14.3 \
|
|
GRADLE_HOME=/opt/gradle/gradle-8.14.3
|
|
RUN mkdir -p /opt/gradle/dist && \
|
|
wget -q "https://services.gradle.org/distributions/gradle-${GRADLE_VERSION}-bin.zip" \
|
|
-O "/opt/gradle/dist/gradle-${GRADLE_VERSION}-bin.zip" && \
|
|
unzip -q "/opt/gradle/dist/gradle-${GRADLE_VERSION}-bin.zip" -d /opt/gradle && \
|
|
"$GRADLE_HOME/bin/gradle" --version
|
|
ENV PATH="$GRADLE_HOME/bin:$PATH"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Desktop packaging tools — kept in a trailing layer ON PURPOSE so that adding
|
|
# or changing a packaging tool doesn't invalidate the expensive apt/rust/Android
|
|
# layers above (a tool tweak becomes a ~1-2 min rebuild, not ~15). Covers Linux
|
|
# (deb/rpm) and Windows cross (MSVC via cargo-xwin + NSIS).
|
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
# Linux desktop packaging: rpmbuild for the .rpm bundle (deb needs nothing extra)
|
|
rpm \
|
|
file \
|
|
# Windows cross-compile (official Tauri path: MSVC target via cargo-xwin).
|
|
# clang provides clang-cl, the MSVC-compatible C compiler cc-rs uses to build
|
|
# C deps (bundled sqlite, ring, ...); lld = linker; llvm = llvm-lib/ar etc;
|
|
# nsis = installer generator.
|
|
clang \
|
|
lld \
|
|
llvm \
|
|
nsis \
|
|
# AppImage bundling. linuxdeploy embeds xdg-open into the AppImage and
|
|
# aborts the whole bundle if it is missing:
|
|
# failed to bundle project: xdg-open binary not found
|
|
# It is present on most desktop distros, which is why the AppImage built on
|
|
# a developer machine and failed here. desktop-file-utils and zsync are the
|
|
# other two linuxdeploy commonly wants (desktop-file-validate, and zsync for
|
|
# delta updates), added together so a missing one does not cost another
|
|
# image rebuild and another failed release build.
|
|
xdg-utils \
|
|
desktop-file-utils \
|
|
zsync \
|
|
&& rm -rf /var/lib/apt/lists/* \
|
|
# Ubuntu's clang package ships clang but NOT the clang-cl alias that cc-rs
|
|
# invokes for MSVC targets. clang-cl is the same binary in MSVC-compat mode,
|
|
# so provide it as a symlink.
|
|
&& ln -sf /usr/bin/clang /usr/local/bin/clang-cl
|
|
|
|
# Windows rust target + cargo-xwin (downloads the MSVC CRT/SDK at build time).
|
|
RUN . $HOME/.cargo/env && \
|
|
rustup target add x86_64-pc-windows-msvc && \
|
|
cargo install --locked cargo-xwin
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Supply-chain and docs tooling.
|
|
#
|
|
# cargo-deny — advisories/licences/bans/sources gate (src-tauri/deny.toml),
|
|
# run by the `security` job. It fetches the RustSec advisory
|
|
# database at run time; that is *data*, not a toolchain, so it
|
|
# does not breach the no-installs-in-CI rule.
|
|
# cargo-cyclonedx — SBOM for the Rust half of a release.
|
|
# mdbook — builds the docs site. It used to be curl'd from GitHub
|
|
# releases *inside* the job (publish-docs.yml), which was both a
|
|
# breach of that rule and a hard dependency on GitHub's CDN
|
|
# being up at publish time. Pinned to the version that job used.
|
|
ENV MDBOOK_VERSION=v0.4.40
|
|
RUN . $HOME/.cargo/env && \
|
|
cargo install --locked cargo-deny cargo-cyclonedx && \
|
|
wget -q "https://github.com/rust-lang/mdBook/releases/download/${MDBOOK_VERSION}/mdbook-${MDBOOK_VERSION}-x86_64-unknown-linux-gnu.tar.gz" \
|
|
-O /tmp/mdbook.tar.gz && \
|
|
tar -xzf /tmp/mdbook.tar.gz -C /usr/local/bin && \
|
|
rm /tmp/mdbook.tar.gz && \
|
|
cargo deny --version && \
|
|
cargo cyclonedx --version && \
|
|
mdbook --version
|
|
|
|
WORKDIR /app
|
|
|
|
ENTRYPOINT ["/bin/bash"]
|