#!/usr/bin/env bash set -euo pipefail BASE_DIR="${BASE_DIR:-/opt/aslan-test}" SRC_DIR="${SRC_DIR:-$BASE_DIR/source/aslan-server}" COMPOSE_FILE="${COMPOSE_FILE:-$BASE_DIR/docker-compose.yml}" ENV_FILE="${ENV_FILE:-$BASE_DIR/config/.env}" LOCK_FILE="${LOCK_FILE:-$BASE_DIR/deploy.lock}" GIT_REMOTE_URL="${GIT_REMOTE_URL:-git@gitea.haiyihy.com:hy/aslan-server.git}" GIT_REF="${GIT_REF:-aslan_test}" ALLOWED_GIT_REFS="${ALLOWED_GIT_REFS:-aslan_test}" MAVEN_GOALS="${MAVEN_GOALS:-clean package}" MAVEN_PROFILE="${MAVEN_PROFILE:-prod}" MAVEN_EXTRA_ARGS="${MAVEN_EXTRA_ARGS:-}" SKIP_BUILD="${SKIP_BUILD:-0}" MODE="${MODE:-compose}" BUILD_TS="${BUILD_TS:-$(date +%Y%m%d%H%M%S)}" ALL_SERVICES=(auth gateway external wallet order live other console) usage() { cat <<'EOF' Usage: deploy-likei-services.sh [--mode compose|build-only|status] [--skip-build] [--fast] [auth|gateway|external|wallet|order|live|other|console ...] Examples: /opt/aslan-test/deploy-likei-services.sh status /opt/aslan-test/deploy-likei-services.sh other /opt/aslan-test/deploy-likei-services.sh --fast other external console GIT_REF=aslan_test /opt/aslan-test/deploy-likei-services.sh auth gateway external wallet order live other console Notes: - This is the single-machine test deployment flow. - It pulls aslan_test, builds local aslan-test/* images, then replaces docker compose app containers. - MySQL/Mongo/Redis/Nacos/RocketMQ are not rebuilt or restarted by this script. EOF } log() { printf '[%s] %s\n' "$(date '+%F %T')" "$*" } need_cmd() { command -v "$1" >/dev/null 2>&1 || { echo "missing command: $1" >&2 exit 2 } } acquire_deploy_lock() { need_cmd flock mkdir -p "$(dirname "$LOCK_FILE")" exec 9>"$LOCK_FILE" # The visual ops panel and manual SSH deploys share this lock so builds cannot interleave. flock -n 9 || { echo "another deploy is already running: $LOCK_FILE" >&2 exit 5 } } validate_git_ref() { if [[ ! "$GIT_REF" =~ ^[A-Za-z0-9._/-]{1,80}$ || "$GIT_REF" == -* || "$GIT_REF" == *..* ]]; then echo "invalid GIT_REF: $GIT_REF" >&2 exit 2 fi local allowed for allowed in $ALLOWED_GIT_REFS; do [[ "$GIT_REF" == "$allowed" ]] && return 0 done echo "GIT_REF is not allowed for test deploy: $GIT_REF (allowed: $ALLOWED_GIT_REFS)" >&2 exit 2 } service_module() { case "$1" in auth) echo "rc-auth" ;; gateway) echo "rc-gateway" ;; external) echo "rc-service/rc-service-external/external-start" ;; wallet) echo "rc-service/rc-service-wallet/wallet-start" ;; order) echo "rc-service/rc-service-order/order-start" ;; live) echo "rc-service/rc-service-live/live-start" ;; other) echo "rc-service/rc-service-other/other-start" ;; console) echo "rc-service/rc-service-console/console-start" ;; *) echo "unsupported service: $1" >&2; exit 2 ;; esac } service_dir() { case "$1" in auth) echo "rc-auth" ;; gateway) echo "rc-gateway" ;; external) echo "rc-service/rc-service-external" ;; wallet) echo "rc-service/rc-service-wallet" ;; order) echo "rc-service/rc-service-order" ;; live) echo "rc-service/rc-service-live" ;; other) echo "rc-service/rc-service-other" ;; console) echo "rc-service/rc-service-console" ;; *) echo "unsupported service: $1" >&2; exit 2 ;; esac } service_image() { case "$1" in auth|gateway|external|wallet|order|live|other|console) echo "aslan-test/$1:latest" ;; *) echo "unsupported service: $1" >&2; exit 2 ;; esac } contains_service() { local needle="$1" local item for item in "${ALL_SERVICES[@]}"; do [[ "$item" == "$needle" ]] && return 0 done return 1 } update_source_from_git() { need_cmd git validate_git_ref [[ -d "$SRC_DIR/.git" ]] || { echo "missing git source: $SRC_DIR" >&2; exit 2; } log "reset source to origin/$GIT_REF from $GIT_REMOTE_URL" git -C "$SRC_DIR" remote set-url origin "$GIT_REMOTE_URL" git -C "$SRC_DIR" fetch origin "$GIT_REF" git -C "$SRC_DIR" checkout -B "$GIT_REF" "origin/$GIT_REF" git -C "$SRC_DIR" reset --hard "origin/$GIT_REF" } package_services() { local services=("$@") local modules=() local svc for svc in "${services[@]}"; do modules+=("$(service_module "$svc")") done local module_csv module_csv="$(IFS=,; echo "${modules[*]}")" if [[ "$SKIP_BUILD" == "1" ]]; then log "skip maven build" return fi cd "$SRC_DIR" log "maven $MAVEN_GOALS -pl $module_csv -P $MAVEN_PROFILE" # The test compose stack still reads the prod-profile Nacos configs; use -P prod unless the caller overrides it. # shellcheck disable=SC2086 mvn $MAVEN_GOALS -pl "$module_csv" -am -P "$MAVEN_PROFILE" -Dmaven.test.skip=true $MAVEN_EXTRA_ARGS } build_image() { local svc="$1" local dir image dir="$(service_dir "$svc")" image="$(service_image "$svc")" cd "$SRC_DIR" log "docker build $image" docker build \ --build-arg "SERVICE_VERSION=aslan-test:${svc}-${BUILD_TS}" \ -f "$dir/Dockerfile" \ -t "$image" \ "$dir" } compose_up() { local services=("$@") cd "$BASE_DIR" log "docker compose recreate: ${services[*]}" docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" up -d --no-deps --force-recreate "${services[@]}" } status() { log "source" git -C "$SRC_DIR" status -sb || true git -C "$SRC_DIR" log -1 --oneline --decorate || true log "compose" docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" ps --format table } main() { local services=() while [[ "$#" -gt 0 ]]; do case "$1" in --mode) [[ -n "${2:-}" ]] || { echo "--mode requires an argument" >&2; exit 2; } MODE="$2" shift 2 ;; --skip-build) SKIP_BUILD=1 shift ;; --fast) MAVEN_GOALS=package shift ;; -h|--help) usage exit 0 ;; status) MODE=status shift ;; *) services+=("$1") shift ;; esac done need_cmd git need_cmd docker [[ -f "$COMPOSE_FILE" ]] || { echo "missing compose file: $COMPOSE_FILE" >&2; exit 2; } [[ -f "$ENV_FILE" ]] || { echo "missing env file: $ENV_FILE" >&2; exit 2; } if [[ "$MODE" == "status" ]]; then status exit 0 fi need_cmd java need_cmd mvn acquire_deploy_lock update_source_from_git if [[ "${#services[@]}" -eq 0 ]]; then services=("${ALL_SERVICES[@]}") fi local svc for svc in "${services[@]}"; do contains_service "$svc" || { echo "unsupported service: $svc" >&2; exit 2; } done package_services "${services[@]}" for svc in "${services[@]}"; do build_image "$svc" done case "$MODE" in compose) compose_up "${services[@]}" ;; build-only) log "build-only completed: ${services[*]}" ;; *) echo "unsupported MODE: $MODE" >&2 exit 2 ;; esac status } main "$@"