Sync all scripts from website downloads — 352 scripts total

Includes updated JS challenge scripts with Claude-User whitelist,
same-site referer bypass, Blackbox-Exporter allowed bot, and all
new exporters, cheat sheets, and automation scripts.
This commit is contained in:
2026-05-25 03:31:08 +02:00
parent dbd6bf0324
commit a1a17e81a1
332 changed files with 174509 additions and 1106 deletions
+726
View File
@@ -0,0 +1,726 @@
#!/usr/bin/env bash
# shellcheck disable=SC2034,SC2015,SC2059
#########################################################################################
#### gitlab-upgrade-path-calculator.sh — Calculate required GitLab upgrade stops ####
#### and PostgreSQL compatibility from 13.x through 18.x ####
#### ####
#### Author: Phil Connor ####
#### Contact: contact@mylinux.work ####
#### License: MIT ####
#### Version 1.00 ####
#### ####
#### Usage: ####
#### ./gitlab-upgrade-path-calculator.sh --from 16.3.0 --to 18.2.0 ####
#### ./gitlab-upgrade-path-calculator.sh --from 15.4.0 --to latest --pg-version 13 ####
#### ./gitlab-upgrade-path-calculator.sh --db-check --from 16.0.0 --pg-version 13 ####
#### ./gitlab-upgrade-path-calculator.sh --list-stops ####
#### ####
#### See --help for all options. ####
#########################################################################################
set -euo pipefail
# ── Defaults ──────────────────────────────────────────────────────────────────
RUN_MODE=""
FROM_VERSION=""
TO_VERSION=""
PG_VERSION=""
DB_SIZE="" # small, medium, large, xlarge
FORMAT="text"
SKIP_CONDITIONAL=false
VERBOSE="${VERBOSE:-false}"
COLOR="${COLOR:-auto}"
SCRIPT_NAME="$(basename "$0")"
# ── Required Upgrade Stops ────────────────────────────────────────────────────
# Format: "version|conditional|notes"
# conditional: 0 = always required, 1 = conditional
STOPS=(
"13.0.14|0|Required stop for 13.x upgrades"
"13.1.11|0|Required stop (CSRF token migration)"
"13.8.8|0|Required stop (duplicate services migration)"
"13.12.15|0|Required stop (last 13.x before 14.0)"
"14.0.12|0|Required stop for 14.x upgrades"
"14.3.6|0|Required stop"
"14.9.5|0|Required stop"
"14.10.5|0|Required stop"
"15.0.5|0|Required stop for 15.x upgrades"
"15.1.6|1|Required only for multi-node instances"
"15.4.6|0|Required stop"
"15.11.13|0|Required stop"
"16.0.10|1|Required only for instances with many users or large pipeline variables"
"16.1.8|1|Required only for instances with NPM packages in package registry"
"16.2.11|1|Required only for instances with large pipeline variables history"
"16.3.9|0|Required stop"
"16.7.10|0|Required stop"
"16.11.10|0|Required stop"
"17.1.8|1|Required only for instances with large ci_pipeline_messages tables"
"17.3.7|0|Required stop"
"17.5.5|0|Required stop"
"17.8.7|0|Required stop"
"17.11.7|0|Required stop"
"18.2.0|0|Required stop (18.x predictable schedule)"
"18.5.0|0|Required stop (18.x predictable schedule)"
"18.8.0|0|Required stop (18.x predictable schedule)"
"18.11.0|0|Required stop (18.x predictable schedule)"
)
# ── PostgreSQL Requirements ───────────────────────────────────────────────────
# Format: "gl_major|pg_min|pg_max"
PG_REQS=(
"13|11|13"
"14|12|13"
"15|12|14"
"16|13|15"
"17|14|16"
"18|16|17"
)
LATEST_VERSION="18.11.0"
# ── Colors ────────────────────────────────────────────────────────────────────
setup_colors() {
if [[ "$COLOR" == "never" ]]; then
RED="" GREEN="" YELLOW="" BLUE="" BOLD="" DIM="" RESET="" CYAN=""
return
fi
if [[ "$COLOR" == "auto" && ! -t 1 ]]; then
RED="" GREEN="" YELLOW="" BLUE="" BOLD="" DIM="" RESET="" CYAN=""
return
fi
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
BOLD='\033[1m'
DIM='\033[2m'
RESET='\033[0m'
}
# ── Logging ───────────────────────────────────────────────────────────────────
log() { printf "${GREEN}%s${RESET}\n" "$*"; }
warn() { printf "${YELLOW}⚠ %s${RESET}\n" "$*" >&2; }
err() { printf "${RED}✗ %s${RESET}\n" "$*" >&2; }
verbose() { [[ "$VERBOSE" == "true" ]] && printf "${DIM} %s${RESET}\n" "$*" >&2 || true; }
die() { err "$*"; exit 1; }
# ── Help ──────────────────────────────────────────────────────────────────────
show_help() {
cat <<EOF
Usage: $SCRIPT_NAME [MODE] [OPTIONS]
Modes:
--path Calculate upgrade path (default when --from/--to given)
--check Auto-detect installed GitLab version, show path to latest
--list-stops List all known required upgrade stops
--db-check Check PostgreSQL compatibility for the upgrade path
Options:
--from VERSION Current GitLab version (e.g., 15.4.0)
--to VERSION Target GitLab version (e.g., 18.2.0 or "latest")
--pg-version VER Current PostgreSQL major version (e.g., 13, 14, 16)
--db-size SIZE Database size: small (<10GB), medium (10-50GB),
large (50-200GB), xlarge (200GB+) — affects migration
time estimates (default: estimates software time only)
--skip-conditional Exclude conditional stops from the path
--format FMT Output format: text, json (default: text)
--no-color Disable colored output
--verbose Debug output
--help Show this help
Environment Variables:
COLOR Color mode: auto, always, never
VERBOSE Debug output (true/false)
Examples:
$SCRIPT_NAME --from 15.4.0 --to 18.2.0
$SCRIPT_NAME --from 16.3.0 --to latest --pg-version 13 --db-size large
$SCRIPT_NAME --check
$SCRIPT_NAME --check --pg-version 14
$SCRIPT_NAME --list-stops
$SCRIPT_NAME --db-check --from 16.0.0 --to 18.5.0 --pg-version 13
$SCRIPT_NAME --from 15.0.0 --to 18.2.0 --format json
$SCRIPT_NAME --from 16.3.0 --to 17.8.7 --skip-conditional
EOF
}
# ── Argument Parsing ──────────────────────────────────────────────────────────
parse_args() {
while [[ $# -gt 0 ]]; do
case "$1" in
--path) RUN_MODE="path"; shift ;;
--check) RUN_MODE="check"; shift ;;
--list-stops) RUN_MODE="list-stops"; shift ;;
--db-check) RUN_MODE="db-check"; shift ;;
--from) FROM_VERSION="$2"; shift 2 ;;
--to) TO_VERSION="$2"; shift 2 ;;
--pg-version) PG_VERSION="${2%%.*}"; shift 2 ;;
--db-size) DB_SIZE="$2"; shift 2 ;;
--skip-conditional) SKIP_CONDITIONAL=true; shift ;;
--format) FORMAT="$2"; shift 2 ;;
--no-color) COLOR="never"; shift ;;
--verbose) VERBOSE="true"; shift ;;
--help) show_help; exit 0 ;;
*) die "Unknown option: $1" ;;
esac
done
if [[ -z "$RUN_MODE" ]]; then
if [[ -n "$FROM_VERSION" || -n "$TO_VERSION" ]]; then
RUN_MODE="path"
else
err "No mode specified"; echo ""; show_help; exit 1
fi
fi
}
# ── Version Helpers ───────────────────────────────────────────────────────────
version_to_int() {
local ver="$1"
local major minor patch
IFS='.' read -r major minor patch <<< "$ver"
patch="${patch:-0}"
printf '%d' $(( major * 10000 + minor * 100 + patch ))
}
version_major() {
echo "${1%%.*}"
}
validate_version() {
local ver="$1"
if [[ ! "$ver" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
die "Invalid version format: $ver (expected X.Y.Z)"
fi
local major
major=$(version_major "$ver")
if (( major < 13 )); then
die "Version $ver is below minimum supported (13.0.0)"
fi
}
# ── Detection ─────────────────────────────────────────────────────────────────
detect_gitlab_version() {
local ver=""
if command -v gitlab-ctl >/dev/null 2>&1; then
ver=$(gitlab-ctl version 2>/dev/null | grep -oP '\d+\.\d+\.\d+' | head -1 || true)
fi
if [[ -z "$ver" ]] && command -v dpkg >/dev/null 2>&1; then
ver=$(dpkg -l gitlab-ce gitlab-ee 2>/dev/null | awk '/^ii/{print $3}' | grep -oP '\d+\.\d+\.\d+' | head -1 || true)
fi
if [[ -z "$ver" ]] && command -v rpm >/dev/null 2>&1; then
ver=$(rpm -q gitlab-ce gitlab-ee 2>/dev/null | grep -oP '\d+\.\d+\.\d+' | head -1 || true)
fi
echo "$ver"
}
detect_pg_version() {
local ver=""
if command -v gitlab-psql >/dev/null 2>&1; then
ver=$(gitlab-psql --version 2>/dev/null | grep -oP '\d+' | head -1 || true)
fi
if [[ -z "$ver" ]] && command -v psql >/dev/null 2>&1; then
ver=$(psql --version 2>/dev/null | grep -oP '\d+' | head -1 || true)
fi
echo "$ver"
}
# ── Core Logic ────────────────────────────────────────────────────────────────
get_pg_req() {
local gl_major="$1"
local entry
for entry in "${PG_REQS[@]}"; do
IFS='|' read -r req_gl req_min req_max <<< "$entry"
if [[ "$req_gl" == "$gl_major" ]]; then
echo "${req_min}|${req_max}"
return
fi
done
echo "unknown|unknown"
}
build_upgrade_path() {
local from_int to_int
from_int=$(version_to_int "$FROM_VERSION")
to_int=$(version_to_int "$TO_VERSION")
UPGRADE_PATH=()
local entry ver ver_int conditional notes
for entry in "${STOPS[@]}"; do
IFS='|' read -r ver conditional notes <<< "$entry"
ver_int=$(version_to_int "$ver")
if (( ver_int <= from_int )); then
continue
fi
if (( ver_int > to_int )); then
continue
fi
if [[ "$SKIP_CONDITIONAL" == "true" && "$conditional" == "1" ]]; then
verbose "Skipping conditional stop: $ver"
continue
fi
UPGRADE_PATH+=("$entry")
done
# Add target if it's not already in the path
local last_ver=""
if [[ ${#UPGRADE_PATH[@]} -gt 0 ]]; then
IFS='|' read -r last_ver _ _ <<< "${UPGRADE_PATH[-1]}"
fi
if [[ "$last_ver" != "$TO_VERSION" ]]; then
UPGRADE_PATH+=("${TO_VERSION}|0|Target version")
fi
}
get_pg_warnings() {
PG_WARNINGS=()
if [[ -z "$PG_VERSION" ]]; then
return
fi
local from_major to_major
from_major=$(version_major "$FROM_VERSION")
to_major=$(version_major "$TO_VERSION")
local gl_major
for (( gl_major = from_major; gl_major <= to_major; gl_major++ )); do
local req
req=$(get_pg_req "$gl_major")
IFS='|' read -r pg_min pg_max <<< "$req"
if [[ "$pg_min" == "unknown" ]]; then
continue
fi
if (( PG_VERSION < pg_min )); then
# Find the last stop before this major version
local boundary_stop=""
local prev_major=$(( gl_major - 1 ))
local entry ver
for entry in "${STOPS[@]}"; do
IFS='|' read -r ver _ _ <<< "$entry"
if [[ "$(version_major "$ver")" == "$prev_major" ]]; then
boundary_stop="$ver"
fi
done
PG_WARNINGS+=("PostgreSQL ${PG_VERSION} is below minimum for GitLab ${gl_major}.x (requires ${pg_min}+)|Upgrade PostgreSQL to ${pg_min}+ before upgrading past GitLab ${boundary_stop:-${prev_major}.x}|${gl_major}|${pg_min}|${pg_max}")
fi
done
}
estimate_downtime() {
local stop_count=${#UPGRADE_PATH[@]}
local pg_upgrade_count=${#PG_WARNINGS[@]}
# Software time: package install + gitlab-ctl reconfigure per stop
DT_SW_LOW=$(( stop_count * 5 ))
DT_SW_HIGH=$(( stop_count * 15 ))
# Background migration time per stop, based on database size
# These run between stops and must complete before proceeding
local mig_low=0 mig_high=0
case "$DB_SIZE" in
small) mig_low=2; mig_high=10 ;; # <10GB: minutes
medium) mig_low=10; mig_high=30 ;; # 10-50GB: tens of minutes
large) mig_low=30; mig_high=90 ;; # 50-200GB: up to hours
xlarge) mig_low=60; mig_high=240 ;; # 200GB+: hours per stop
*) mig_low=0; mig_high=0 ;; # unknown: show software only
esac
DT_MIG_LOW=$(( stop_count * mig_low ))
DT_MIG_HIGH=$(( stop_count * mig_high ))
# PostgreSQL major upgrade time
DT_PG_LOW=$(( pg_upgrade_count * 15 ))
DT_PG_HIGH=$(( pg_upgrade_count * 60 ))
DT_GL_LOW=$(( DT_SW_LOW + DT_MIG_LOW ))
DT_GL_HIGH=$(( DT_SW_HIGH + DT_MIG_HIGH ))
DT_TOTAL_LOW=$(( DT_GL_LOW + DT_PG_LOW ))
DT_TOTAL_HIGH=$(( DT_GL_HIGH + DT_PG_HIGH ))
}
# ── Text Output ───────────────────────────────────────────────────────────────
print_header() {
printf "\n${BOLD}GitLab Upgrade Path Calculator${RESET}\n"
printf "══════════════════════════════════════════════════════════════\n\n"
}
format_path_text() {
print_header
printf " ${BOLD}From:${RESET} %s\n" "$FROM_VERSION"
printf " ${BOLD}To:${RESET} %s\n" "$TO_VERSION"
printf " ${BOLD}Stops:${RESET} %d\n" "${#UPGRADE_PATH[@]}"
if [[ -n "$PG_VERSION" ]]; then
if [[ ${#PG_WARNINGS[@]} -gt 0 ]]; then
local last_warn="${PG_WARNINGS[-1]}"
IFS='|' read -r _ _ _ final_pg_min _ <<< "$last_warn"
printf "\n ${BOLD}PostgreSQL:${RESET} ${YELLOW}Currently ${PG_VERSION} → Must upgrade to ${final_pg_min}+ before GitLab ${TO_VERSION}${RESET}\n"
else
printf "\n ${BOLD}PostgreSQL:${RESET} ${GREEN}${PG_VERSION} — compatible with target${RESET}\n"
fi
fi
printf "\n ── Upgrade Path ──────────────────────────────────────────\n\n"
printf " ${DIM}Step Version Notes PG Required${RESET}\n"
printf " ${DIM}──── ──────────── ─────────────────────────────────────── ──────────${RESET}\n"
local step=0 entry ver conditional notes
for entry in "${UPGRADE_PATH[@]}"; do
IFS='|' read -r ver conditional notes <<< "$entry"
step=$((step + 1))
local gl_major pg_range
gl_major=$(version_major "$ver")
local req
req=$(get_pg_req "$gl_major")
IFS='|' read -r pg_min pg_max <<< "$req"
if [[ "$pg_min" != "unknown" ]]; then
pg_range="${pg_min}-${pg_max}"
else
pg_range="—"
fi
local cond_marker=""
if [[ "$conditional" == "1" ]]; then
cond_marker=" ⓘ"
fi
local ver_color="$RESET"
if [[ "$notes" == "Target version" ]]; then
ver_color="$GREEN"
fi
printf " %3d ${ver_color}%-12s${RESET} %-39s %s\n" "$step" "$ver" "${notes}${cond_marker}" "$pg_range"
done
if [[ ${#PG_WARNINGS[@]} -gt 0 ]]; then
printf "\n ── PostgreSQL Upgrade Required ───────────────────────────\n\n"
local warning
for warning in "${PG_WARNINGS[@]}"; do
IFS='|' read -r msg action gl_major pg_min pg_max <<< "$warning"
printf " ${YELLOW}⚠ %s${RESET}\n" "$msg"
printf " → %s\n\n" "$action"
done
fi
estimate_downtime
printf " ── Estimated Downtime ────────────────────────────────────\n\n"
printf " Software: %d stops × 5-15 min = %d-%d min\n" "${#UPGRADE_PATH[@]}" "$DT_SW_LOW" "$DT_SW_HIGH"
printf " ${DIM}(package install + gitlab-ctl reconfigure)${RESET}\n"
if [[ -n "$DB_SIZE" ]]; then
printf " Migrations: %d stops × %s db = %d-%d min\n" "${#UPGRADE_PATH[@]}" "$DB_SIZE" "$DT_MIG_LOW" "$DT_MIG_HIGH"
printf " ${DIM}(background migrations must complete per stop)${RESET}\n"
else
printf " Migrations: ${DIM}use --db-size (small/medium/large/xlarge) for estimates${RESET}\n"
fi
if [[ ${#PG_WARNINGS[@]} -gt 0 ]]; then
printf " PG upgrades: %d × 15-60 min = %d-%d min\n" "${#PG_WARNINGS[@]}" "$DT_PG_LOW" "$DT_PG_HIGH"
fi
printf "\n ${BOLD}Total estimate: %d-%d min${RESET}" "$DT_TOTAL_LOW" "$DT_TOTAL_HIGH"
if (( DT_TOTAL_HIGH >= 120 )); then
local hours_low=$(( DT_TOTAL_LOW / 60 ))
local hours_high=$(( DT_TOTAL_HIGH / 60 ))
printf " (%d-%d hrs — plan a full maintenance window)" "$hours_low" "$hours_high"
fi
printf "\n\n"
if [[ "$SKIP_CONDITIONAL" == "false" ]]; then
local has_conditional=false
for entry in "${UPGRADE_PATH[@]}"; do
IFS='|' read -r _ conditional _ <<< "$entry"
if [[ "$conditional" == "1" ]]; then
has_conditional=true
break
fi
done
if [[ "$has_conditional" == "true" ]]; then
printf " ${DIM}ⓘ = conditional stop (may be skippable — use --skip-conditional)${RESET}\n\n"
fi
fi
}
format_path_json() {
local steps_json="["
local step=0 first=true entry ver conditional notes
for entry in "${UPGRADE_PATH[@]}"; do
IFS='|' read -r ver conditional notes <<< "$entry"
step=$((step + 1))
local gl_major req pg_min pg_max
gl_major=$(version_major "$ver")
req=$(get_pg_req "$gl_major")
IFS='|' read -r pg_min pg_max <<< "$req"
[[ "$first" == "true" ]] || steps_json+=","
first=false
steps_json+=$(printf '{"step":%d,"version":"%s","conditional":%s,"notes":"%s","pg_min":"%s","pg_max":"%s"}' \
"$step" "$ver" "$( [[ "$conditional" == "1" ]] && echo "true" || echo "false" )" "$notes" "$pg_min" "$pg_max")
done
steps_json+="]"
local pg_upgrades_json="["
first=true
if [[ ${#PG_WARNINGS[@]} -gt 0 ]]; then
local warning
for warning in "${PG_WARNINGS[@]}"; do
IFS='|' read -r msg action gl_major pg_min pg_max <<< "$warning"
[[ "$first" == "true" ]] || pg_upgrades_json+=","
first=false
pg_upgrades_json+=$(printf '{"before_gitlab":"%s.0.0","min_pg":"%s","max_pg":"%s"}' "$gl_major" "$pg_min" "$pg_max")
done
fi
pg_upgrades_json+="]"
estimate_downtime
printf '{\n'
printf ' "from": "%s",\n' "$FROM_VERSION"
printf ' "to": "%s",\n' "$TO_VERSION"
printf ' "total_stops": %d,\n' "${#UPGRADE_PATH[@]}"
printf ' "pg_current": "%s",\n' "${PG_VERSION:-null}"
printf ' "pg_upgrades_needed": %s,\n' "$pg_upgrades_json"
printf ' "steps": %s,\n' "$steps_json"
printf ' "db_size": "%s",\n' "${DB_SIZE:-unknown}"
printf ' "estimated_downtime_min": {"software": {"low": %d, "high": %d}, "migrations": {"low": %d, "high": %d}, "pg_upgrades": {"low": %d, "high": %d}, "total": {"low": %d, "high": %d}}\n' \
"$DT_SW_LOW" "$DT_SW_HIGH" "$DT_MIG_LOW" "$DT_MIG_HIGH" "$DT_PG_LOW" "$DT_PG_HIGH" "$DT_TOTAL_LOW" "$DT_TOTAL_HIGH"
printf '}\n'
}
# ── Mode: --path ──────────────────────────────────────────────────────────────
run_path() {
if [[ -z "$FROM_VERSION" ]]; then
verbose "Detecting installed GitLab version..."
FROM_VERSION=$(detect_gitlab_version)
if [[ -z "$FROM_VERSION" ]]; then
die "Could not detect installed GitLab version. Use --from VERSION."
fi
log "Detected GitLab version: $FROM_VERSION"
fi
if [[ -z "$TO_VERSION" || "$TO_VERSION" == "latest" ]]; then
TO_VERSION="$LATEST_VERSION"
fi
validate_version "$FROM_VERSION"
validate_version "$TO_VERSION"
local from_int to_int
from_int=$(version_to_int "$FROM_VERSION")
to_int=$(version_to_int "$TO_VERSION")
if (( from_int >= to_int )); then
die "Target version ($TO_VERSION) must be higher than current version ($FROM_VERSION)"
fi
build_upgrade_path
get_pg_warnings
if [[ "$FORMAT" == "json" ]]; then
format_path_json
else
format_path_text
fi
}
# ── Mode: --check ─────────────────────────────────────────────────────────────
run_check() {
verbose "Detecting installed GitLab version..."
FROM_VERSION=$(detect_gitlab_version)
if [[ -z "$FROM_VERSION" ]]; then
die "Could not detect installed GitLab version. Use --path --from VERSION instead."
fi
log "Detected GitLab version: $FROM_VERSION"
if [[ -z "$PG_VERSION" ]]; then
verbose "Detecting PostgreSQL version..."
PG_VERSION=$(detect_pg_version)
if [[ -n "$PG_VERSION" ]]; then
log "Detected PostgreSQL version: $PG_VERSION"
fi
fi
if [[ -z "$TO_VERSION" || "$TO_VERSION" == "latest" ]]; then
TO_VERSION="$LATEST_VERSION"
fi
validate_version "$FROM_VERSION"
validate_version "$TO_VERSION"
build_upgrade_path
get_pg_warnings
if [[ "$FORMAT" == "json" ]]; then
format_path_json
else
format_path_text
fi
}
# ── Mode: --list-stops ────────────────────────────────────────────────────────
run_list_stops() {
print_header
printf " ── All Known Required Upgrade Stops ──────────────────────\n\n"
printf " ${DIM}Version Type Notes PG Required${RESET}\n"
printf " ${DIM}──────────── ──────────── ─────────────────────────────────────── ──────────${RESET}\n"
local entry ver conditional notes
for entry in "${STOPS[@]}"; do
IFS='|' read -r ver conditional notes <<< "$entry"
local gl_major req pg_min pg_max pg_range type_label
gl_major=$(version_major "$ver")
req=$(get_pg_req "$gl_major")
IFS='|' read -r pg_min pg_max <<< "$req"
if [[ "$pg_min" != "unknown" ]]; then
pg_range="${pg_min}-${pg_max}"
else
pg_range="—"
fi
if [[ "$conditional" == "1" ]]; then
type_label="${YELLOW}conditional${RESET} "
else
type_label="${GREEN}required${RESET} "
fi
printf " %-12s %b %-39s %s\n" "$ver" "$type_label" "$notes" "$pg_range"
done
printf "\n ── PostgreSQL Version Requirements ───────────────────────\n\n"
printf " ${DIM}GitLab Min PG Max PG${RESET}\n"
printf " ${DIM}───────── ──────── ────────${RESET}\n"
local pg_entry
for pg_entry in "${PG_REQS[@]}"; do
IFS='|' read -r gl_major pg_min pg_max <<< "$pg_entry"
printf " %-9s %-8s %s\n" "${gl_major}.x" "$pg_min" "$pg_max"
done
printf "\n"
}
# ── Mode: --db-check ──────────────────────────────────────────────────────────
run_db_check() {
if [[ -z "$PG_VERSION" ]]; then
verbose "Detecting PostgreSQL version..."
PG_VERSION=$(detect_pg_version)
if [[ -z "$PG_VERSION" ]]; then
die "Could not detect PostgreSQL version. Use --pg-version VERSION."
fi
log "Detected PostgreSQL version: $PG_VERSION"
fi
if [[ -z "$FROM_VERSION" ]]; then
FROM_VERSION=$(detect_gitlab_version)
if [[ -z "$FROM_VERSION" ]]; then
die "Could not detect GitLab version. Use --from VERSION."
fi
log "Detected GitLab version: $FROM_VERSION"
fi
if [[ -z "$TO_VERSION" || "$TO_VERSION" == "latest" ]]; then
TO_VERSION="$LATEST_VERSION"
fi
validate_version "$FROM_VERSION"
validate_version "$TO_VERSION"
build_upgrade_path
get_pg_warnings
if [[ "$FORMAT" == "json" ]]; then
local pg_json="["
local first=true
if [[ ${#PG_WARNINGS[@]} -gt 0 ]]; then
local warning
for warning in "${PG_WARNINGS[@]}"; do
IFS='|' read -r msg action gl_major pg_min pg_max <<< "$warning"
[[ "$first" == "true" ]] || pg_json+=","
first=false
pg_json+=$(printf '{"message":"%s","action":"%s","gitlab_major":"%s","pg_min":"%s","pg_max":"%s"}' \
"$msg" "$action" "$gl_major" "$pg_min" "$pg_max")
done
fi
pg_json+="]"
printf '{"pg_current":"%s","from":"%s","to":"%s","compatible":%s,"warnings":%s}\n' \
"$PG_VERSION" "$FROM_VERSION" "$TO_VERSION" \
"$( [[ ${#PG_WARNINGS[@]} -eq 0 ]] && echo "true" || echo "false" )" "$pg_json"
return
fi
print_header
printf " ${BOLD}PostgreSQL Compatibility Check${RESET}\n\n"
printf " Current GitLab: %s\n" "$FROM_VERSION"
printf " Target GitLab: %s\n" "$TO_VERSION"
printf " Current PostgreSQL: %s\n\n" "$PG_VERSION"
local from_major to_major
from_major=$(version_major "$FROM_VERSION")
to_major=$(version_major "$TO_VERSION")
printf " ── Requirements by GitLab Version ────────────────────────\n\n"
printf " ${DIM}GitLab Min PG Max PG Your PG %s Status${RESET}\n" "$PG_VERSION"
printf " ${DIM}───────── ──────── ──────── ────────── ──────────${RESET}\n"
local gl_major
for (( gl_major = from_major; gl_major <= to_major; gl_major++ )); do
local req pg_min pg_max status
req=$(get_pg_req "$gl_major")
IFS='|' read -r pg_min pg_max <<< "$req"
if (( PG_VERSION < pg_min )); then
status="${RED}✗ Too low${RESET}"
elif (( PG_VERSION > pg_max )); then
status="${YELLOW}⚠ Too high${RESET}"
else
status="${GREEN}✓ OK${RESET}"
fi
printf " %-9s %-8s %-8s %-10s %b\n" "${gl_major}.x" "$pg_min" "$pg_max" "$PG_VERSION" "$status"
done
if [[ ${#PG_WARNINGS[@]} -gt 0 ]]; then
printf "\n ── Action Required ───────────────────────────────────────\n\n"
local warning
for warning in "${PG_WARNINGS[@]}"; do
IFS='|' read -r msg action gl_major pg_min pg_max <<< "$warning"
printf " ${YELLOW}⚠ %s${RESET}\n" "$msg"
printf " → %s\n\n" "$action"
done
else
printf "\n ${GREEN}✓ PostgreSQL %s is compatible with the full upgrade path.${RESET}\n\n" "$PG_VERSION"
fi
}
# ── Main ──────────────────────────────────────────────────────────────────────
main() {
setup_colors
parse_args "$@"
setup_colors
case "$RUN_MODE" in
path) run_path ;;
check) run_check ;;
list-stops) run_list_stops ;;
db-check) run_db_check ;;
*) die "Unknown mode: $RUN_MODE" ;;
esac
}
main "$@"