收紧分支环境安装流程
This commit is contained in:
+52
-61
@@ -152,7 +152,7 @@ ${C_BOLD}选项:${C_RESET}
|
||||
dev/main 默认 http://127.0.0.1:8888
|
||||
release 必须通过此参数或交互输入提供
|
||||
${C_WHITE}--yes${C_RESET} 跳过所有交互确认,适合 CI/CD 自动化执行
|
||||
${C_WHITE}--skip-build${C_RESET} 跳过镜像重新构建(docker compose up -d)
|
||||
${C_WHITE}--skip-build${C_RESET} 跳过镜像构建,仍会启动容器(docker compose up -d)
|
||||
${C_WHITE}--skip-migrate${C_RESET} 跳过数据库迁移(alembic upgrade head)
|
||||
${C_WHITE}--verbose${C_RESET} 展开所有命令的实时输出(默认折叠为 spinner)
|
||||
${C_WHITE}-h, --help${C_RESET} 显示此帮助信息
|
||||
@@ -279,13 +279,36 @@ read_env_value() {
|
||||
' "$ENV_FILE"
|
||||
}
|
||||
|
||||
normalize_private_key_to_stdout() {
|
||||
printf '%b' "$1"
|
||||
}
|
||||
resolve_effective_config() {
|
||||
local desired_project_name="$1"
|
||||
local desired_runtime_env="$2"
|
||||
local desired_login_key_id="$3"
|
||||
|
||||
private_key_is_valid() {
|
||||
[[ -n "$1" ]] || return 1
|
||||
normalize_private_key_to_stdout "$1" | openssl rsa -check -noout >/dev/null 2>&1
|
||||
EFFECTIVE_PROJECT_NAME="$desired_project_name"
|
||||
EFFECTIVE_RUNTIME_ENV="$desired_runtime_env"
|
||||
EFFECTIVE_LOGIN_KEY_ID="$desired_login_key_id"
|
||||
|
||||
[[ -f "$ENV_FILE" ]] || return 0
|
||||
|
||||
local env_project_name env_runtime_env env_login_key_id
|
||||
env_project_name="$(read_env_value COMPOSE_PROJECT_NAME || true)"
|
||||
env_runtime_env="$(read_env_value ENV || true)"
|
||||
env_login_key_id="$(read_env_value LOGIN_RSA_KEY_ID || true)"
|
||||
|
||||
[[ -n "$env_project_name" ]] || fail ".env 缺少 COMPOSE_PROJECT_NAME,请补齐后重试"
|
||||
[[ -n "$env_runtime_env" ]] || fail ".env 缺少 ENV,请补齐后重试"
|
||||
[[ -n "$env_login_key_id" ]] || fail ".env 缺少 LOGIN_RSA_KEY_ID,请补齐后重试"
|
||||
|
||||
if [[ "$env_project_name" != "$desired_project_name" ]]; then
|
||||
fail ".env 的 COMPOSE_PROJECT_NAME=$env_project_name 与目标环境 $TARGET_ENV 期望值 $desired_project_name 不一致"
|
||||
fi
|
||||
if [[ "$env_runtime_env" != "$desired_runtime_env" ]]; then
|
||||
fail ".env 的 ENV=$env_runtime_env 与目标环境 $TARGET_ENV 期望值 $desired_runtime_env 不一致"
|
||||
fi
|
||||
|
||||
EFFECTIVE_PROJECT_NAME="$env_project_name"
|
||||
EFFECTIVE_RUNTIME_ENV="$env_runtime_env"
|
||||
EFFECTIVE_LOGIN_KEY_ID="$env_login_key_id"
|
||||
}
|
||||
|
||||
generate_escaped_private_key() {
|
||||
@@ -323,7 +346,7 @@ confirm_install() {
|
||||
step "确认安装参数"
|
||||
|
||||
local env_status build_status migrate_status
|
||||
env_status="$([[ -f "$ENV_FILE" ]] && printf '已存在(将备份后重写)' || printf '不存在(将新建)')"
|
||||
env_status="$([[ -f "$ENV_FILE" ]] && printf '已存在' || printf '新建')"
|
||||
build_status="$([[ "$SKIP_BUILD" -eq 1 ]] && printf '跳过' || printf '执行')"
|
||||
migrate_status="$([[ "$SKIP_MIGRATE" -eq 1 ]] && printf '跳过' || printf '执行')"
|
||||
|
||||
@@ -333,7 +356,7 @@ confirm_install() {
|
||||
printf ' %s%-18s%s %s\n' "${C_BOLD}" "Compose 项目" "${C_RESET}" "$project_name"
|
||||
printf ' %s%-18s%s %s\n' "${C_BOLD}" "健康检查地址" "${C_RESET}" "$BASE_URL"
|
||||
printf ' %s%-18s%s %s\n' "${C_BOLD}" ".env 文件" "${C_RESET}" "$env_status"
|
||||
printf ' %s%-18s%s %s\n' "${C_BOLD}" "pg_data 目录" "${C_RESET}" "$([[ -d "$ROOT_DIR/pg_data" ]] && printf '已存在(保留)' || printf '不存在')"
|
||||
printf ' %s%-18s%s %s\n' "${C_BOLD}" "pg_data 目录" "${C_RESET}" "$([[ -d "$ROOT_DIR/pg_data" ]] && printf '已存在' || printf '新建')"
|
||||
printf ' %s%-18s%s %s\n' "${C_BOLD}" "镜像构建" "${C_RESET}" "$build_status"
|
||||
printf ' %s%-18s%s %s\n' "${C_BOLD}" "数据库迁移" "${C_RESET}" "$migrate_status"
|
||||
printf '\n'
|
||||
@@ -352,40 +375,12 @@ confirm_install() {
|
||||
|
||||
# ── .env 写入 ─────────────────────────────────
|
||||
|
||||
backup_env_file() {
|
||||
if [[ -f "$ENV_FILE" ]]; then
|
||||
local backup_file
|
||||
backup_file="$ENV_FILE.bak.$(date +%Y%m%d%H%M%S)"
|
||||
cp "$ENV_FILE" "$backup_file"
|
||||
ok "已备份现有 .env → $(basename "$backup_file")"
|
||||
fi
|
||||
}
|
||||
|
||||
write_env_file() {
|
||||
local project_name="$1" runtime_env="$2" login_key_id="$3"
|
||||
local jwt_secret="$4" rsa_private_key="$5"
|
||||
local temp_file
|
||||
temp_file="$(mktemp "$ROOT_DIR/.env.tmp.XXXXXX")"
|
||||
|
||||
if [[ -f "$ENV_FILE" ]]; then
|
||||
awk '
|
||||
BEGIN {
|
||||
prefixes[1] = "COMPOSE_PROJECT_NAME="
|
||||
prefixes[2] = "ENV="
|
||||
prefixes[3] = "JWT_SECRET_KEY="
|
||||
prefixes[4] = "LOGIN_RSA_KEY_ID="
|
||||
prefixes[5] = "LOGIN_RSA_PRIVATE_KEY="
|
||||
}
|
||||
{
|
||||
drop = 0
|
||||
for (i = 1; i <= 5; i++) {
|
||||
if (index($0, prefixes[i]) == 1) { drop = 1; break }
|
||||
}
|
||||
if (!drop) print
|
||||
}
|
||||
' "$ENV_FILE" > "$temp_file"
|
||||
fi
|
||||
|
||||
{
|
||||
printf 'COMPOSE_PROJECT_NAME=%s\n' "$project_name"
|
||||
printf 'ENV=%s\n' "$runtime_env"
|
||||
@@ -403,31 +398,23 @@ prepare_env_file() {
|
||||
local project_name="$1" runtime_env="$2" login_key_id="$3"
|
||||
local jwt_secret="" rsa_private_key=""
|
||||
|
||||
if [[ -f "$ENV_FILE" ]]; then
|
||||
ok "检测到现有 .env,保留原文件并跳过写入"
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ "$TARGET_ENV" == "dev" ]]; then
|
||||
jwt_secret="dev-secret"
|
||||
rsa_private_key=""
|
||||
else
|
||||
jwt_secret="$(read_env_value JWT_SECRET_KEY || true)"
|
||||
if [[ -z "$jwt_secret" || "$jwt_secret" == "dev-secret" ]]; then
|
||||
jwt_secret="$(generate_jwt_secret)"
|
||||
ok "已生成新的 JWT_SECRET_KEY"
|
||||
else
|
||||
ok "保留现有 JWT_SECRET_KEY"
|
||||
fi
|
||||
jwt_secret="$(generate_jwt_secret)"
|
||||
ok "已生成新的 JWT_SECRET_KEY"
|
||||
|
||||
rsa_private_key="$(read_env_value LOGIN_RSA_PRIVATE_KEY || true)"
|
||||
if [[ -z "$rsa_private_key" ]]; then
|
||||
log "正在生成 RSA 2048 密钥对,请稍候…"
|
||||
rsa_private_key="$(generate_escaped_private_key)"
|
||||
ok "已生成新的 LOGIN_RSA_PRIVATE_KEY"
|
||||
elif private_key_is_valid "$rsa_private_key"; then
|
||||
ok "保留现有有效 LOGIN_RSA_PRIVATE_KEY"
|
||||
else
|
||||
fail "现有 LOGIN_RSA_PRIVATE_KEY 不是合法的 PEM 私钥,请修复 .env 后重试(脚本不会自动覆盖已有密钥)"
|
||||
fi
|
||||
log "正在生成 RSA 2048 密钥对,请稍候…"
|
||||
rsa_private_key="$(generate_escaped_private_key)"
|
||||
ok "已生成新的 LOGIN_RSA_PRIVATE_KEY"
|
||||
fi
|
||||
|
||||
backup_env_file
|
||||
write_env_file "$project_name" "$runtime_env" "$login_key_id" "$jwt_secret" "$rsa_private_key"
|
||||
}
|
||||
|
||||
@@ -440,13 +427,13 @@ run_compose_config() {
|
||||
|
||||
run_backend_init() {
|
||||
[[ "$TARGET_ENV" != "dev" ]] || return 0
|
||||
step "初始化生产数据库与管理员账号"
|
||||
step "初始化数据库与管理员账号"
|
||||
run_quiet "运行 backend-init 容器" -- docker compose run --rm backend-init
|
||||
}
|
||||
|
||||
run_build_and_start() {
|
||||
if [[ "$SKIP_BUILD" -eq 1 ]]; then
|
||||
step "启动服务(跳过镜像重新构建)"
|
||||
step "启动服务(跳过镜像构建)"
|
||||
run_quiet "启动容器" -- docker compose up -d
|
||||
else
|
||||
step "构建镜像并启动服务"
|
||||
@@ -519,9 +506,11 @@ check_http_endpoint() {
|
||||
local path="$1"
|
||||
local url="${BASE_URL%/}$path"
|
||||
log "探测接口: $url"
|
||||
local attempt=1 max_attempts=10 delay=2
|
||||
local attempt=1 max_attempts=10 delay=2 warmup_delay=3
|
||||
log "等待服务预热 ${warmup_delay}s …"
|
||||
sleep "$warmup_delay"
|
||||
while [[ "$attempt" -le "$max_attempts" ]]; do
|
||||
if curl -fsS "$url" >/dev/null; then
|
||||
if curl -fsS "$url" >/dev/null 2>&1; then
|
||||
ok "接口就绪: $path"
|
||||
return 0
|
||||
fi
|
||||
@@ -575,14 +564,16 @@ main() {
|
||||
login_key_id="$(key_id)"
|
||||
|
||||
resolve_base_url
|
||||
resolve_effective_config "$project_name" "$runtime_env" "$login_key_id"
|
||||
check_dependencies
|
||||
confirm_install "$project_name" "$runtime_env"
|
||||
confirm_install "$EFFECTIVE_PROJECT_NAME" "$EFFECTIVE_RUNTIME_ENV"
|
||||
prepare_env_file "$project_name" "$runtime_env" "$login_key_id"
|
||||
run_compose_config
|
||||
run_backend_init
|
||||
run_build_and_start
|
||||
run_migrations
|
||||
run_health_checks "$runtime_env" "$login_key_id"
|
||||
resolve_effective_config "$project_name" "$runtime_env" "$login_key_id"
|
||||
run_health_checks "$EFFECTIVE_RUNTIME_ENV" "$EFFECTIVE_LOGIN_KEY_ID"
|
||||
show_success
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user