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.
139 lines
5.7 KiB
Bash
Executable file
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)"
|