From ba3ae8b3e6b61d3835bd240380467d3e210e8524 Mon Sep 17 00:00:00 2001 From: Hank Date: Wed, 8 Jul 2026 11:05:35 -0700 Subject: [PATCH] CI: dedicated cached runner for this repo (deploy script + volume caches) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - scripts/deploy-runner.sh: compose-managed BigBrainParking Forgejo runner (adapted from the Camp Scan one), with valid_volumes for bigbrainparking-gradle and bigbrainparking-npm. No android-sdk volume — the RN build image ships it. - Workflow mounts those caches (GRADLE_USER_HOME + npm cache) and enables the Gradle build cache (org.gradle.caching + --build-cache), so repeat builds skip the dep re-download and recompile that dominate a cold ~35 min build. Co-Authored-By: Claude Fable 5 --- .forgejo/workflows/build-apk.yml | 13 ++- scripts/deploy-runner.sh | 149 +++++++++++++++++++++++++++++++ 2 files changed, 161 insertions(+), 1 deletion(-) create mode 100755 scripts/deploy-runner.sh diff --git a/.forgejo/workflows/build-apk.yml b/.forgejo/workflows/build-apk.yml index 785e6aa..6e34f9c 100644 --- a/.forgejo/workflows/build-apk.yml +++ b/.forgejo/workflows/build-apk.yml @@ -26,6 +26,15 @@ jobs: # and NO container swap (--memory-swap == --memory) so it OOM-fails cleanly # instead of thrashing the disk with swap. With the JVM caps below it uses ~5 GB. options: --cpus=2 --memory=8g --memory-swap=8g + # Persistent caches (whitelisted in the runner's config.yaml valid_volumes). + # Gradle home = downloaded Maven deps + build cache; npm = package cache. + # Repeat builds skip the re-download/re-compile that dominate a cold build. + volumes: + - bigbrainparking-gradle:/opt/cache/gradle + - bigbrainparking-npm:/opt/cache/npm + env: + GRADLE_USER_HOME: /opt/cache/gradle + npm_config_cache: /opt/cache/npm steps: - uses: actions/checkout@v4 @@ -60,6 +69,7 @@ jobs: org.gradle.workers.max=2 org.gradle.parallel=false org.gradle.daemon=false + org.gradle.caching=true kotlin.daemon.jvmargs=-Xmx1536m PROPS @@ -73,10 +83,11 @@ jobs: # Also cap the no-daemon launcher JVM (org.gradle.jvmargs targets the daemon). GRADLE_OPTS: "-Xmx1536m -Djava.net.preferIPv4Stack=true" # --max-workers=2 limits concurrent tasks; container --cpus=2 caps clang -j. + # --build-cache reuses task outputs from GRADLE_USER_HOME across runs. run: >- ./gradlew :app:assembleRelease -PreactNativeArchitectures=arm64-v8a - --no-daemon --max-workers=2 + --no-daemon --max-workers=2 --build-cache # Self-contained publish via the Forgejo API (no external action to fetch). - name: Publish release + upload APK diff --git a/scripts/deploy-runner.sh b/scripts/deploy-runner.sh new file mode 100755 index 0000000..935493b --- /dev/null +++ b/scripts/deploy-runner.sh @@ -0,0 +1,149 @@ +#!/usr/bin/env bash +# +# Deploy the BigBrainParking Forgejo Actions runner on a host (Ubuntu/Debian). +# Self-contained: installs Docker if missing, writes the runner compose + env, +# registers against git.mowden.top, and starts the runner. +# +# Usage: +# sudo bash deploy-runner.sh [INSTALL_DIR] +# +# REGISTRATION_TOKEN From Forgejo -> hank/BigBrainParking -> +# Settings -> Actions -> Runners -> Create new runner. +# INSTALL_DIR Where to place the runner (default /opt/bigbrainparking-runner). +# +# Re-running is safe: it updates files and restarts. The token is only consumed +# on the first registration (stored afterwards in /data/.runner). +# +# NOTE: this host also runs the Camp Scan runner and several databases on a small +# box (20 GB / 4 cores). The BigBrainParking build workflow hard-caps itself to +# --cpus=2 --memory=8g, but if a Camp Scan build and a BigBrainParking build run +# at the SAME time they'll together want ~4 cores / ~16 GB. Keep an eye on that, +# or lower the caps in .forgejo/workflows/build-apk.yml if the box gets tight. +set -euo pipefail + +FORGEJO_INSTANCE="https://git.mowden.top" +RUNNER_IMAGE="code.forgejo.org/forgejo/runner:6.3.1" +RUNNER_NAME="${RUNNER_NAME:-$(hostname)-bigbrainparking}" +JOB_LABEL="docker:docker://node:22-bookworm" + +TOKEN="${1:-${REGISTRATION_TOKEN:-}}" +INSTALL_DIR="${2:-/opt/bigbrainparking-runner}" + +log() { printf '\033[1;32m==>\033[0m %s\n' "$*"; } +err() { printf '\033[1;31mERROR:\033[0m %s\n' "$*" >&2; } + +if [ "$(id -u)" -ne 0 ]; then + err "Run with sudo/root (needs to install packages and access the Docker socket)." + exit 1 +fi + +if [ -z "$TOKEN" ] && [ ! -f "$INSTALL_DIR/data/.runner" ]; then + err "No registration token given and no existing registration found." + echo "Usage: sudo bash deploy-runner.sh [INSTALL_DIR]" >&2 + exit 1 +fi + +# --- 1. Docker --------------------------------------------------------------- +if ! command -v docker >/dev/null 2>&1; then + log "Installing Docker (get.docker.com)..." + curl -fsSL https://get.docker.com | sh + systemctl enable --now docker +else + log "Docker already installed: $(docker --version)" +fi + +if ! docker compose version >/dev/null 2>&1; then + log "Installing docker compose plugin..." + apt-get update -y + apt-get install -y docker-compose-plugin +fi + +DOCKER_GID="$(stat -c '%g' /var/run/docker.sock)" +log "Docker socket group id: $DOCKER_GID" + +# --- 2. Files ---------------------------------------------------------------- +log "Writing runner files to $INSTALL_DIR" +mkdir -p "$INSTALL_DIR/data" +# The runner image runs as uid/gid 1000 and must own its config dir. +chown -R 1000:1000 "$INSTALL_DIR/data" + +# Runner config: allow the build workflow to mount the persistent cache volumes +# (Gradle home = Maven deps + build cache, npm cache) so APK builds don't +# redownload and recompile everything each run. Without valid_volumes listed, +# the runner rejects the workflow's `volumes:` and the job fails. +# (No android-sdk volume: the build image already ships the Android SDK/NDK.) +cat > "$INSTALL_DIR/config.yaml" <<'CONFIG' +container: + valid_volumes: + - bigbrainparking-gradle + - bigbrainparking-npm +CONFIG +chown 1000:1000 "$INSTALL_DIR/config.yaml" + +# Pre-create the named cache volumes (idempotent). +docker volume create bigbrainparking-gradle >/dev/null +docker volume create bigbrainparking-npm >/dev/null + +cat > "$INSTALL_DIR/docker-compose.yml" < "$INSTALL_DIR/.env" <&1 | tail -8 + +cat <