#!/usr/bin/env bash set -u -o pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" CLIENT_DIR="$ROOT_DIR/client" SERVER_DIR="$ROOT_DIR/server" PUBLIC_BASE_URL="${LIVE_SMOKE_BASE_URL:-https://oa.hyinda.com}" REPORT_DIR="${LAUNCH_AUTO_REPORT_DIR:-$ROOT_DIR/artifacts/qa-flow/launch-auto-ops-$(date +%Y%m%d-%H%M%S)}" SUMMARY_TXT="$REPORT_DIR/summary.txt" STATUS=0 mkdir -p "$REPORT_DIR" : >"$SUMMARY_TXT" load_default_env() { local env_file="${LAUNCH_AUTO_ENV_FILE:-$HOME/.hyb-oa/live-smoke.env}" if [[ "${LAUNCH_AUTO_SKIP_ENV_FILE:-0}" == "1" || ! -f "$env_file" ]]; then return 0 fi set -a # shellcheck disable=SC1090 source "$env_file" set +a PUBLIC_BASE_URL="${LIVE_SMOKE_BASE_URL:-$PUBLIC_BASE_URL}" echo "[launch-auto-ops] loaded masked env file" | tee -a "$SUMMARY_TXT" } run_step() { local name="$1" shift local log_file="$REPORT_DIR/${name}.log" echo ">>> [launch-auto-ops] $name" | tee -a "$SUMMARY_TXT" if "$@" > >(tee "$log_file") 2>&1; then echo "[launch-auto-ops][PASS] $name" | tee -a "$SUMMARY_TXT" else local code="$?" echo "[launch-auto-ops][FAIL] $name exit=$code" | tee -a "$SUMMARY_TXT" STATUS=1 fi } run_shell_step() { local name="$1" local command="$2" run_step "$name" bash -lc "$command" } write_summary_json() { local qa_status="PASS" local notes="LAUTO GO_TO_OPERATE:正式启用后自动化巡检通过;payment_batch_v1 保持 force_on,erp_sync 保持 force_off;企微打卡同步缺外部配置时按 SKIP 记录。" if [[ "$STATUS" -ne 0 ]]; then qa_status="FAIL" notes="LAUTO PAUSE_FOR_FIX:正式启用后自动化巡检存在失败;未执行生产恢复、数据库重置、真实支付或 ERP 操作。" fi QA_REPORT_DIR="$REPORT_DIR" \ QA_ISSUE_ID="${QA_ISSUE_ID:-LAUTO}" \ QA_BASE_URL="$PUBLIC_BASE_URL" \ QA_MODE="launch-auto-ops" \ QA_STATUS="$qa_status" \ QA_SUMMARY_NOTES="$notes" \ node "$ROOT_DIR/scripts/qa/write-qa-summary.mjs" >/dev/null 2>&1 || true } finish() { write_summary_json echo "[launch-auto-ops] report=$REPORT_DIR" | tee -a "$SUMMARY_TXT" exit "$STATUS" } trap finish EXIT load_default_env run_shell_step "backend-prisma" "cd '$SERVER_DIR' && npm run prisma:validate" run_shell_step "backend-node-check" "cd '$SERVER_DIR' && node --check src/routes/attendance.js src/routes/attendanceCorrections.js src/routes/paymentBatches.js src/routes/exports.js src/routes/wecomAuth.js" run_shell_step "backend-focused-tests" "cd '$SERVER_DIR' && npm test -- tests/unit/routes/attendance.test.js tests/unit/routes/attendanceCorrections.test.js tests/unit/routes/paymentBatches.reimbursement.test.js tests/unit/routes/exports.apOperations.test.js tests/unit/routes/wecomAuth.test.js tests/unit/routes/notifications.test.js" if [[ "${LAUNCH_AUTO_SKIP_BUILD:-0}" == "1" ]]; then echo "[launch-auto-ops][SKIP] frontend-build LAUNCH_AUTO_SKIP_BUILD=1" | tee -a "$SUMMARY_TXT" else run_shell_step "frontend-typecheck" "cd '$CLIENT_DIR' && npm run typecheck" run_shell_step "frontend-build" "cd '$CLIENT_DIR' && npm run build" fi if [[ "${LAUNCH_AUTO_SKIP_LIVE:-0}" == "1" ]]; then echo "[launch-auto-ops][SKIP] live checks LAUNCH_AUTO_SKIP_LIVE=1" | tee -a "$SUMMARY_TXT" else run_shell_step "live-env-strict" "LIVE_SMOKE_BASE_URL='$PUBLIC_BASE_URL' node '$ROOT_DIR/scripts/qa/check-live-smoke-env.mjs' --strict" run_shell_step "live-readiness" "QA_ISSUE_ID='${QA_ISSUE_ID:-LAUTO}' LIVE_SMOKE_BASE_URL='$PUBLIC_BASE_URL' bash '$ROOT_DIR/scripts/qa/run-live-smoke-readiness.sh'" run_shell_step "live-feature-flags" "LIVE_SMOKE_BASE_URL='$PUBLIC_BASE_URL' node '$ROOT_DIR/scripts/qa/check-live-feature-flags.mjs' --expect payment_batch_v1=force_on --expect erp_sync=force_off --expect attendance_v1=disabled --expect attendance_unified_v1=enabled" run_shell_step "live-attendance-unified" "LIVE_SMOKE_BASE_URL='$PUBLIC_BASE_URL' node '$ROOT_DIR/scripts/qa/check-live-attendance-unified.mjs' --json" if [[ "$STATUS" -ne 0 ]]; then echo "[launch-auto-ops][SKIP] payment-batch-force-on-flow skipped because previous live gate failed" | tee -a "$SUMMARY_TXT" elif [[ "${LAUNCH_AUTO_ALLOW_PUBLIC_WRITES:-0}" != "1" ]]; then echo "[launch-auto-ops][FAIL] payment-batch-live-write requires LAUNCH_AUTO_ALLOW_PUBLIC_WRITES=1" | tee -a "$SUMMARY_TXT" STATUS=1 else run_shell_step "payment-batch-force-on-flow" "cd '$CLIENT_DIR' && PLAYWRIGHT_MANUAL=1 E2E_MODE=live P2_FIN_LIVE_APPROVED=1 P2_FIN_LIVE_ALREADY_ON=1 P2_FIN_LIVE_FINAL_STATE=force_on QA_ISSUE_ID='${QA_ISSUE_ID:-LAUTO}' P2_FIN_LIVE_MARKER_PREFIX='${LAUNCH_AUTO_MARKER_PREFIX:-LAUNCHAUTO}' P2_FIN_LIVE_REPORT_DIR='$REPORT_DIR' LIVE_SMOKE_BASE_URL='$PUBLIC_BASE_URL' npx playwright test tests/e2e/manual/p2-fin-live-payment-batch.spec.ts --workers=1 --reporter=list" fi run_shell_step "public-mobile-matrix" "cd '$CLIENT_DIR' && E2E_BASE_URL='$PUBLIC_BASE_URL' npx playwright test tests/e2e/dg7-mobile-information-dedupe.spec.ts tests/e2e/r124-mobile-entry-matrix.spec.ts --workers=1 --reporter=list" run_shell_step "wecom-rendering-matrix" "cd '$CLIENT_DIR' && E2E_BASE_URL='$PUBLIC_BASE_URL' npx playwright test tests/e2e/r6-wecom-mobile-rendering-hardening.spec.ts --workers=1 --reporter=list" fi