forgejo-stack/setup.sh
forgejo_admin 5c3e33ced3 feat(runner): add Android-augmented job image (#1)
Adds opt-in Android job image so workflows like exifcleaner-web's APK build skip the ~3-5 min cold Android SDK install per run.

- runner-image-android/Dockerfile inherits forgejo-stack/job:latest, adds JDK 17 Temurin + Android cmdline-tools + platforms;android-35 + build-tools;35.0.0
- setup.sh builds forgejo-stack/job-android:latest after the main image (gated on RUNNER_BUILD_ANDROID_IMAGE, default true)
- .env.example documents the new vars; .gitignore adds .worktrees/

Consumers opt in via container: forgejo-stack/job-android:latest at the job level. Default forgejo-stack/job:latest stays slim.
2026-05-17 15:41:18 +04:00

139 lines
5.7 KiB
Bash
Executable file

#!/usr/bin/env bash
# setup.sh — idempotent bootstrap for the forgejo-stack.
# Usage:
# ./setup.sh # fresh install or top-up
# ./setup.sh --restore # data dirs already exist, only re-register MCP & memory
# ./setup.sh --mcp=native # use host-installed forgejo-mcp instead of container
set -euo pipefail
HERE="$(cd "$(dirname "$0")" && pwd)"
cd "$HERE"
# shellcheck source=scripts/lib.sh
source "$HERE/scripts/lib.sh"
MODE="install"
MCP_MODE="container"
for arg in "$@"; do
case "$arg" in
--restore) MODE="restore" ;;
--mcp=container) MCP_MODE="container" ;;
--mcp=native) MCP_MODE="native" ;;
-h|--help)
sed -n '2,5p' "$0"; exit 0 ;;
*) log_err "unknown arg: $arg"; exit 2 ;;
esac
done
require_tools docker curl jq awk
# 1. Create .env from .env.example if missing
if [[ ! -f .env ]]; then
log_info "creating .env from .env.example"
cp .env.example .env
fi
# 2. Fill blank secret values with random ones (idempotent — only blanks)
fill_if_empty() {
local key="$1" gen_fn="$2"
local current
current=$(awk -F= -v k="$key" '$1==k{print substr($0,length(k)+2)}' .env)
# Strip leading whitespace and trailing inline comment so that
# "KEY= # comment" parses as empty.
current="${current#"${current%%[![:space:]]*}"}"
if [[ "$current" == \#* ]]; then current=""; fi
if [[ -z "$current" ]]; then
local val; val="$($gen_fn)"
env_set .env "$key" "$val"
log_info "generated $key"
fi
}
fill_if_empty FORGEJO_ADMIN_PASSWORD gen_password
fill_if_empty FORGEJO_SECRET_KEY gen_secret
fill_if_empty FORGEJO_INTERNAL_TOKEN gen_secret
fill_if_empty FORGEJO_JWT_SECRET gen_secret
fill_if_empty FORGEJO_LFS_JWT_SECRET gen_secret
fill_if_empty POSTGRES_PASSWORD gen_password
fill_if_empty CLAUDE_BOT_PASSWORD gen_password
fill_if_empty GEMINI_BOT_PASSWORD gen_password
load_env
# 3. Create data dirs with correct ownership (Forgejo container uses 1000:1000)
for sub in forgejo db runner; do
mkdir -p "data/$sub"
done
# chown only if we have permission (sudo not required for our own dirs)
if [[ "$(stat -c %u data/forgejo 2>/dev/null || echo 0)" != "1000" ]]; then
log_info "fixing data/ ownership to 1000:1000 (may prompt for sudo)"
sudo chown -R 1000:1000 data/forgejo data/runner || log_warn "chown failed; continuing — adjust manually if Forgejo can't write"
fi
# 4. Build the job image used by Forgejo Actions runners. Adds yarn on top of
# catthehacker/ubuntu:runner-22.04 so Node workflows work out of the box.
JOB_IMAGE_TAG="${RUNNER_JOB_IMAGE:-forgejo-stack/job:latest}"
if ! docker image inspect "$JOB_IMAGE_TAG" >/dev/null 2>&1; then
log_info "building runner job image: $JOB_IMAGE_TAG"
docker build -t "$JOB_IMAGE_TAG" runner-image/
else
log_info "runner job image already present: $JOB_IMAGE_TAG"
fi
# 4-android. Build the Android-augmented job image. Inherits the main image
# (Node 22 + yarn + Playwright) and adds JDK 17 + Android SDK so workflows
# that opt in via `container: forgejo-stack/job-android:latest` skip the
# ~3-5 min cold Android SDK install per run. Default is opt-out for the
# base job image — non-Android workflows pay no disk cost.
#
# Set RUNNER_BUILD_ANDROID_IMAGE=false to skip (e.g. CI hosts that don't
# serve Android workflows).
ANDROID_JOB_IMAGE_TAG="${RUNNER_ANDROID_JOB_IMAGE:-forgejo-stack/job-android:latest}"
if [[ "${RUNNER_BUILD_ANDROID_IMAGE:-true}" == "true" ]]; then
if ! docker image inspect "$ANDROID_JOB_IMAGE_TAG" >/dev/null 2>&1; then
log_info "building android runner job image: $ANDROID_JOB_IMAGE_TAG (this takes ~5 min)"
docker build -t "$ANDROID_JOB_IMAGE_TAG" runner-image-android/
else
log_info "android runner job image already present: $ANDROID_JOB_IMAGE_TAG"
fi
else
log_info "skipping android runner job image (RUNNER_BUILD_ANDROID_IMAGE=false)"
fi
# 4a. Seed the hostedtoolcache volume from the job image's baked
# /opt/hostedtoolcache. Docker only auto-initialises a named volume from
# the FIRST container that mounts it; runner-1 (image forgejo/runner:6)
# has no baked toolcache, so without explicit seeding the empty volume
# would shadow Node 22 in every job container. Only seeds once — to
# refresh after a job-image rebuild, `docker volume rm` first.
TOOLCACHE_VOLUME="${RUNNER_HOSTEDTOOLCACHE_VOLUME:-forgejo-stack-hostedtoolcache}"
if ! docker volume inspect "$TOOLCACHE_VOLUME" >/dev/null 2>&1; then
log_info "seeding $TOOLCACHE_VOLUME from $JOB_IMAGE_TAG"
docker volume create "$TOOLCACHE_VOLUME" >/dev/null
docker run --rm -v "$TOOLCACHE_VOLUME":/dst "$JOB_IMAGE_TAG" \
sh -c 'cp -a /opt/hostedtoolcache/. /dst/ 2>/dev/null || true; chmod -R a+rwX /dst'
fi
# 5. Bring the stack up
log_info "starting compose stack"
docker compose up -d
# 6. Wait for Forgejo to be healthy
log_info "waiting for Forgejo HTTP API"
wait_for_url "${FORGEJO_ROOT_URL%/}/api/v1/version" 180
# 6a. Prime the runner image's yarn offline cache from the configured consumer
# repo(s), if any. No-op when RUNNER_CACHE_SEED_REPOS is unset or when the
# repos don't exist yet (first-run before bootstrap creates them).
# The runner-refresh compose service keeps this current afterwards.
if [[ -n "${RUNNER_CACHE_SEED_REPOS:-}" ]]; then
log_info "priming runner image yarn cache (repos: $RUNNER_CACHE_SEED_REPOS)"
RUNNER_JOB_IMAGE="$JOB_IMAGE_TAG" bash "$HERE/scripts/refresh-runner-image.sh" || \
log_warn "initial cache prime failed; runner-refresh will retry"
fi
# 7. Run bootstrap
log_info "running bootstrap-forgejo.sh (mode=$MODE)"
MODE="$MODE" MCP_MODE="$MCP_MODE" bash "$HERE/scripts/bootstrap-forgejo.sh"
log_info "setup complete. Forgejo at ${FORGEJO_ROOT_URL}"
log_info "admin user: ${FORGEJO_ADMIN_USER} password: see .env (FORGEJO_ADMIN_PASSWORD)"