Persist configure_runners values incrementally

This commit is contained in:
S
2026-03-01 08:15:32 -05:00
parent f4a6b04d14
commit 66febf69bb

View File

@@ -4,7 +4,7 @@ set -euo pipefail
# =============================================================================
# setup/configure_runners.sh — Interactive runners.conf configuration wizard
# Prompts for each runner's fields with validation and progress tracking.
# Writes INI-style runners.conf (see runners.conf.example for format).
# Persists answers to runners.conf as each prompt is completed.
# Defaults are pulled from .env — nothing is hardcoded.
# =============================================================================
@@ -32,15 +32,36 @@ fi
# If runners.conf already exists and is INI format, we read existing values
# to pre-fill prompts when re-running the wizard.
# ---------------------------------------------------------------------------
DEFAULTS_CONF=""
cleanup_defaults_conf() {
if [[ -n "$DEFAULTS_CONF" ]] && [[ -f "$DEFAULTS_CONF" ]]; then
rm -f "$DEFAULTS_CONF"
fi
}
trap cleanup_defaults_conf EXIT
EXISTING_SECTIONS=()
if [[ -f "$RUNNERS_CONF" ]]; then
# Keep a snapshot for defaults so we can rewrite runners.conf incrementally
# without losing pre-filled values when the wizard is re-run.
DEFAULTS_CONF=$(mktemp)
cp "$RUNNERS_CONF" "$DEFAULTS_CONF"
while IFS= read -r sec; do
[[ -z "$sec" ]] && continue
EXISTING_SECTIONS+=("$sec")
done < <(ini_list_sections "$RUNNERS_CONF")
done < <(ini_list_sections "$DEFAULTS_CONF")
fi
EXISTING_COUNT=${#EXISTING_SECTIONS[@]}
ini_default_get() {
local section="$1" key="$2" default="${3:-}"
if [[ -z "$DEFAULTS_CONF" ]]; then
printf '%s' "$default"
return 0
fi
ini_get "$DEFAULTS_CONF" "$section" "$key" "$default"
}
# ---------------------------------------------------------------------------
# Validation helpers
# ---------------------------------------------------------------------------
@@ -180,6 +201,31 @@ prompt_field() {
PROMPT_RESULT="$value"
}
init_runners_conf() {
cat > "$RUNNERS_CONF" <<'HEADER'
# =============================================================================
# runners.conf — Gitea Actions Runner Definitions (INI format)
# Generated by setup/configure_runners.sh — edit manually or re-run wizard.
# Use manage_runner.sh to add/remove runners dynamically.
# See runners.conf.example for field reference.
# =============================================================================
HEADER
}
ensure_runner_section() {
local section="$1"
if ! grep -Fqx "[$section]" "$RUNNERS_CONF" 2>/dev/null; then
printf '[%s]\n\n' "$section" >> "$RUNNERS_CONF"
fi
}
save_runner_field() {
local section="$1" key="$2" value="$3"
ini_set "$RUNNERS_CONF" "$section" "$key" "$value"
COLLECTED_DATA["${section}:${key}"]="$value"
}
# ===========================================================================
# Main
# ===========================================================================
@@ -218,12 +264,14 @@ fi
TOTAL_PROMPTS=$((runner_count * 10))
# ---------------------------------------------------------------------------
# Collect runner definitions
# Configure runner definitions
# ---------------------------------------------------------------------------
# Storage arrays for collected INI data
# Keep arrays for end-of-run summary; values are persisted immediately.
COLLECTED_NAMES=()
declare -A COLLECTED_DATA # COLLECTED_DATA["name:key"] = value
init_runners_conf
for ((i = 0; i < runner_count; i++)); do
runner_num=$((i + 1))
printf '\n%b── RUNNER %d OF %d ──────────────────────────────────────────%b\n' "$C_BOLD" "$runner_num" "$runner_count" "$C_RESET"
@@ -244,11 +292,12 @@ for ((i = 0; i < runner_count; i++)); do
prompt_field "name" "runner display name in Gitea" "runner_name" "$name_default"
r_name="$PROMPT_RESULT"
COLLECTED_NAMES+=("$r_name")
ensure_runner_section "$r_name"
# --- host ---
host_default=""
if [[ -n "$ex_name" ]]; then
host_default=$(ini_get "$RUNNERS_CONF" "$ex_name" "host" "")
host_default=$(ini_default_get "$ex_name" "host" "")
fi
if [[ -z "$host_default" ]]; then
case $i in
@@ -260,7 +309,7 @@ for ((i = 0; i < runner_count; i++)); do
fi
prompt_field "host" "unraid, fedora, local, or custom" "runner_host" "$host_default"
r_host="$PROMPT_RESULT"
COLLECTED_DATA["${r_name}:host"]="$r_host"
save_runner_field "$r_name" "host" "$r_host"
# Show resolved SSH details for known hosts
case "$r_host" in
@@ -286,19 +335,19 @@ for ((i = 0; i < runner_count; i++)); do
ex_ssh_port=""
ex_ssh_key=""
if [[ -n "$ex_name" ]]; then
ex_ssh_host=$(ini_get "$RUNNERS_CONF" "$ex_name" "ssh_host" "")
ex_ssh_user=$(ini_get "$RUNNERS_CONF" "$ex_name" "ssh_user" "")
ex_ssh_port=$(ini_get "$RUNNERS_CONF" "$ex_name" "ssh_port" "22")
ex_ssh_key=$(ini_get "$RUNNERS_CONF" "$ex_name" "ssh_key" "")
ex_ssh_host=$(ini_default_get "$ex_name" "ssh_host" "")
ex_ssh_user=$(ini_default_get "$ex_name" "ssh_user" "")
ex_ssh_port=$(ini_default_get "$ex_name" "ssh_port" "22")
ex_ssh_key=$(ini_default_get "$ex_name" "ssh_key" "")
fi
prompt_field "ssh_host" "IP address of remote host" "ip" "$ex_ssh_host"
COLLECTED_DATA["${r_name}:ssh_host"]="$PROMPT_RESULT"
save_runner_field "$r_name" "ssh_host" "$PROMPT_RESULT"
prompt_field "ssh_user" "SSH username" "nonempty" "${ex_ssh_user:-root}"
COLLECTED_DATA["${r_name}:ssh_user"]="$PROMPT_RESULT"
save_runner_field "$r_name" "ssh_user" "$PROMPT_RESULT"
prompt_field "ssh_port" "SSH port" "port" "${ex_ssh_port:-22}"
COLLECTED_DATA["${r_name}:ssh_port"]="$PROMPT_RESULT"
save_runner_field "$r_name" "ssh_port" "$PROMPT_RESULT"
prompt_field "ssh_key" "path to SSH key (empty = ssh-agent)" "optional_path" "$ex_ssh_key" "true"
COLLECTED_DATA["${r_name}:ssh_key"]="$PROMPT_RESULT"
save_runner_field "$r_name" "ssh_key" "$PROMPT_RESULT"
# Adjust total prompts (added 4 custom fields, but we already allocated 10)
;;
esac
@@ -306,19 +355,19 @@ for ((i = 0; i < runner_count; i++)); do
# --- type ---
type_default=""
if [[ -n "$ex_name" ]]; then
type_default=$(ini_get "$RUNNERS_CONF" "$ex_name" "type" "")
type_default=$(ini_default_get "$ex_name" "type" "")
fi
if [[ -z "$type_default" ]]; then
if [[ "$r_host" == "local" ]]; then type_default="native"; else type_default="docker"; fi
fi
prompt_field "type" "docker (Linux) or native (macOS)" "runner_type" "$type_default"
r_type="$PROMPT_RESULT"
COLLECTED_DATA["${r_name}:type"]="$r_type"
save_runner_field "$r_name" "type" "$r_type"
# --- data_path ---
path_default=""
if [[ -n "$ex_name" ]]; then
path_default=$(ini_get "$RUNNERS_CONF" "$ex_name" "data_path" "")
path_default=$(ini_default_get "$ex_name" "data_path" "")
fi
if [[ -z "$path_default" ]]; then
if [[ "$r_type" == "native" ]]; then
@@ -328,39 +377,39 @@ for ((i = 0; i < runner_count; i++)); do
fi
fi
prompt_field "data_path" "absolute path for runner data" "runner_path" "$path_default"
COLLECTED_DATA["${r_name}:data_path"]="$PROMPT_RESULT"
save_runner_field "$r_name" "data_path" "$PROMPT_RESULT"
# --- labels ---
labels_default=""
if [[ -n "$ex_name" ]]; then
labels_default=$(ini_get "$RUNNERS_CONF" "$ex_name" "labels" "")
labels_default=$(ini_default_get "$ex_name" "labels" "")
fi
if [[ -z "$labels_default" ]]; then
if [[ "$r_type" == "native" ]]; then labels_default="macos"; else labels_default="linux"; fi
fi
prompt_field "labels" "workflow runs-on value" "nonempty" "$labels_default"
COLLECTED_DATA["${r_name}:labels"]="$PROMPT_RESULT"
save_runner_field "$r_name" "labels" "$PROMPT_RESULT"
# --- default_image (skip for native) ---
if [[ "$r_type" == "docker" ]]; then
image_default=""
if [[ -n "$ex_name" ]]; then
image_default=$(ini_get "$RUNNERS_CONF" "$ex_name" "default_image" "")
image_default=$(ini_default_get "$ex_name" "default_image" "")
fi
if [[ -z "$image_default" ]]; then
image_default="${RUNNER_DEFAULT_IMAGE:-catthehacker/ubuntu:act-latest}"
fi
prompt_field "default_image" "Docker image for job execution" "nonempty" "$image_default"
COLLECTED_DATA["${r_name}:default_image"]="$PROMPT_RESULT"
save_runner_field "$r_name" "default_image" "$PROMPT_RESULT"
else
COLLECTED_DATA["${r_name}:default_image"]=""
save_runner_field "$r_name" "default_image" ""
CURRENT_PROMPT=$((CURRENT_PROMPT + 1)) # skip but count for progress
fi
# --- repos ---
repos_default=""
if [[ -n "$ex_name" ]]; then
repos_default=$(ini_get "$RUNNERS_CONF" "$ex_name" "repos" "all")
repos_default=$(ini_default_get "$ex_name" "repos" "all")
fi
if [[ -z "$repos_default" ]]; then repos_default="all"; fi
# Build hint with known repo names
@@ -371,29 +420,29 @@ for ((i = 0; i < runner_count; i++)); do
fi
done
prompt_field "repos" "$repos_hint" "runner_repos" "$repos_default"
COLLECTED_DATA["${r_name}:repos"]="$PROMPT_RESULT"
save_runner_field "$r_name" "repos" "$PROMPT_RESULT"
# --- capacity ---
cap_default=""
if [[ -n "$ex_name" ]]; then
cap_default=$(ini_get "$RUNNERS_CONF" "$ex_name" "capacity" "")
cap_default=$(ini_default_get "$ex_name" "capacity" "")
fi
if [[ -z "$cap_default" ]]; then
cap_default="${RUNNER_DEFAULT_CAPACITY:-1}"
fi
prompt_field "capacity" "max concurrent jobs (>= 1)" "capacity" "$cap_default"
COLLECTED_DATA["${r_name}:capacity"]="$PROMPT_RESULT"
save_runner_field "$r_name" "capacity" "$PROMPT_RESULT"
# --- cpu (skip for native) ---
if [[ "$r_type" == "docker" ]]; then
cpu_default=""
if [[ -n "$ex_name" ]]; then
cpu_default=$(ini_get "$RUNNERS_CONF" "$ex_name" "cpu" "")
cpu_default=$(ini_default_get "$ex_name" "cpu" "")
fi
prompt_field "cpu" "Docker CPU limit (e.g. 2.0, empty = no limit)" "docker_cpu" "$cpu_default" "true"
COLLECTED_DATA["${r_name}:cpu"]="$PROMPT_RESULT"
save_runner_field "$r_name" "cpu" "$PROMPT_RESULT"
else
COLLECTED_DATA["${r_name}:cpu"]=""
save_runner_field "$r_name" "cpu" ""
CURRENT_PROMPT=$((CURRENT_PROMPT + 1))
fi
@@ -401,49 +450,16 @@ for ((i = 0; i < runner_count; i++)); do
if [[ "$r_type" == "docker" ]]; then
mem_default=""
if [[ -n "$ex_name" ]]; then
mem_default=$(ini_get "$RUNNERS_CONF" "$ex_name" "memory" "")
mem_default=$(ini_default_get "$ex_name" "memory" "")
fi
prompt_field "memory" "Docker memory limit (e.g. 2g, empty = no limit)" "docker_memory" "$mem_default" "true"
COLLECTED_DATA["${r_name}:memory"]="$PROMPT_RESULT"
save_runner_field "$r_name" "memory" "$PROMPT_RESULT"
else
COLLECTED_DATA["${r_name}:memory"]=""
save_runner_field "$r_name" "memory" ""
CURRENT_PROMPT=$((CURRENT_PROMPT + 1))
fi
done
# ---------------------------------------------------------------------------
# Write runners.conf — INI format with header comment block
# ---------------------------------------------------------------------------
cat > "$RUNNERS_CONF" <<'HEADER'
# =============================================================================
# runners.conf — Gitea Actions Runner Definitions (INI format)
# Generated by setup/configure_runners.sh — edit manually or re-run wizard.
# Use manage_runner.sh to add/remove runners dynamically.
# See runners.conf.example for field reference.
# =============================================================================
HEADER
for r_name in "${COLLECTED_NAMES[@]}"; do
printf '[%s]\n' "$r_name" >> "$RUNNERS_CONF"
# Write fields in canonical order
for key in host type data_path labels default_image repos capacity cpu memory; do
local_val="${COLLECTED_DATA["${r_name}:${key}"]:-}"
printf '%-14s= %s\n' "$key" "$local_val" >> "$RUNNERS_CONF"
done
# Write custom SSH fields if host=custom
if [[ "${COLLECTED_DATA["${r_name}:host"]:-}" == "custom" ]]; then
for key in ssh_host ssh_user ssh_port ssh_key; do
local_val="${COLLECTED_DATA["${r_name}:${key}"]:-}"
printf '%-14s= %s\n' "$key" "$local_val" >> "$RUNNERS_CONF"
done
fi
printf '\n' >> "$RUNNERS_CONF"
done
# ===========================================================================
# Summary — green border box + table
# ===========================================================================