#!/usr/bin/env bash set -Eeuo pipefail GITEA_URL="${GITEA_URL:-https://git.awaioi.com/}" GITEA_REPOSITORY="${GITEA_REPOSITORY:-awaioi/ERP}" RUNNER_IMAGE="${RUNNER_IMAGE:-}" RUNNER_CONTAINER="${RUNNER_CONTAINER:-gitea-runner}" RUNNER_VOLUME="${RUNNER_VOLUME:-gitea-runner-data}" RUNNER_LABELS="${RUNNER_LABELS:-ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest}" log() { printf '[Gitea Runner] %s\n' "$*" } fail() { printf '[Gitea Runner] ERROR: %s\n' "$*" >&2 exit 1 } command -v docker >/dev/null 2>&1 || fail "docker is not installed" docker info >/dev/null 2>&1 || fail "docker is not running or the current user cannot access it" find_gitea_container() { local container_id image name while read -r container_id image name; do case "$image" in gitea/gitea:* | gitea/gitea@* | */gitea/gitea:* | */gitea/gitea@* | docker.gitea.com/gitea:* | docker.gitea.com/gitea@*) printf '%s\n' "$container_id" return 0 ;; esac done < <(docker ps --format '{{.ID}} {{.Image}} {{.Names}}') while read -r container_id name; do case "$name" in *runner*) ;; *gitea*) printf '%s\n' "$container_id" return 0 ;; esac done < <(docker ps --format '{{.ID}} {{.Names}}') return 1 } pull_runner_image() { local candidate local -a candidates if [[ -n "$RUNNER_IMAGE" ]]; then candidates=("$RUNNER_IMAGE") else candidates=( "docker.gitea.com/runner:3.0.2" "docker.gitea.com/act_runner:3.0.2" "gitea/runner:3.0.2" ) fi for candidate in "${candidates[@]}"; do log "Pulling $candidate" if docker pull "$candidate"; then RUNNER_IMAGE="$candidate" return 0 fi log "Image source failed; trying the next source" done fail "all official Gitea Runner image sources failed" } GITEA_CONTAINER="$(find_gitea_container || true)" [[ -n "$GITEA_CONTAINER" ]] || fail "no running Gitea container was found" TMP_DIR="$(mktemp -d)" TOKEN_FILE="$TMP_DIR/runner-token" BOOTSTRAP_RUNNING=0 cleanup() { if [[ "$BOOTSTRAP_RUNNING" == "1" ]]; then docker rm -f "$RUNNER_CONTAINER" >/dev/null 2>&1 || true fi if [[ -f "$TOKEN_FILE" ]]; then : >"$TOKEN_FILE" fi rm -rf -- "$TMP_DIR" } trap cleanup EXIT log "Generating a repository-scoped registration token" if ! docker exec -u git "$GITEA_CONTAINER" gitea actions generate-runner-token \ --scope "$GITEA_REPOSITORY" | tr -d '\r' | tail -n 1 >"$TOKEN_FILE"; then fail "Gitea could not generate a runner token" fi [[ -s "$TOKEN_FILE" ]] || fail "Gitea returned an empty runner token" chmod 600 "$TOKEN_FILE" pull_runner_image docker rm -f "$RUNNER_CONTAINER" >/dev/null 2>&1 || true docker volume create "$RUNNER_VOLUME" >/dev/null docker run --rm --entrypoint /bin/rm \ -v "$RUNNER_VOLUME:/data" \ "$RUNNER_IMAGE" -f /data/.runner log "Registering the runner" docker run -d \ --name "$RUNNER_CONTAINER" \ -v "$RUNNER_VOLUME:/data" \ -v "$TOKEN_FILE:/run/secrets/gitea_runner_token:ro,Z" \ -v /var/run/docker.sock:/var/run/docker.sock \ -e "GITEA_INSTANCE_URL=$GITEA_URL" \ -e GITEA_RUNNER_REGISTRATION_TOKEN_FILE=/run/secrets/gitea_runner_token \ -e "GITEA_RUNNER_NAME=erp-release-$(hostname -s)" \ -e "GITEA_RUNNER_LABELS=$RUNNER_LABELS" \ -e GITEA_MAX_REG_ATTEMPTS=24 \ "$RUNNER_IMAGE" >/dev/null BOOTSTRAP_RUNNING=1 READY=0 for ((attempt = 1; attempt <= 60; attempt++)); do if docker exec "$RUNNER_CONTAINER" test -s /data/.runner 2>/dev/null; then READY=1 break fi if [[ "$(docker inspect -f '{{.State.Running}}' "$RUNNER_CONTAINER" 2>/dev/null || true)" != "true" ]]; then break fi sleep 2 done if [[ "$READY" != "1" ]]; then docker logs --tail 100 "$RUNNER_CONTAINER" >&2 || true fail "runner registration failed" fi docker logs --tail 30 "$RUNNER_CONTAINER" || true docker rm -f "$RUNNER_CONTAINER" >/dev/null BOOTSTRAP_RUNNING=0 : >"$TOKEN_FILE" log "Starting the persistent runner without the registration token" docker run -d \ --name "$RUNNER_CONTAINER" \ --restart unless-stopped \ -v "$RUNNER_VOLUME:/data" \ -v /var/run/docker.sock:/var/run/docker.sock \ -e "GITEA_INSTANCE_URL=$GITEA_URL" \ -e "GITEA_RUNNER_NAME=erp-release-$(hostname -s)" \ -e "GITEA_RUNNER_LABELS=$RUNNER_LABELS" \ "$RUNNER_IMAGE" >/dev/null sleep 5 [[ "$(docker inspect -f '{{.State.Running}}' "$RUNNER_CONTAINER")" == "true" ]] || { docker logs --tail 100 "$RUNNER_CONTAINER" >&2 || true fail "runner container stopped after registration" } log "Runner is online; queued release jobs can now continue" docker ps --filter "name=^/${RUNNER_CONTAINER}$" \ --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}' docker logs --tail 80 "$RUNNER_CONTAINER" || true