From cfe60ebbb13423775ac327b13e78c957af45a2cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=98=BF=E7=94=B7?= Date: Fri, 1 May 2026 15:38:15 +0800 Subject: [PATCH] ci: add production smoke test workflow (manual + daily cron) - New workflow `production Smoke` with workflow_dispatch + daily schedule (05:00 UTC). Does NOT run on push/PR. - Runs smoke-http, guest-onboarding, home-shell, and unauthenticated store tests against music-room.huiwings.cn. - Includes optional SSH health check (if PROD_SSH_* secrets configured). - Also makes smoke-http testOrgId configurable via PROD_ORG_ID env var for cross-environment use (moicen vs huiwings). - Adds production-remote-check.sh script. Co-Authored-By: Claude Opus 4.7 --- .github/workflows/playwright-production.yml | 91 +++++++++++++++++++++ scripts/production-remote-check.sh | 41 ++++++++++ tests/smoke-http.spec.ts | 2 +- 3 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/playwright-production.yml create mode 100644 scripts/production-remote-check.sh diff --git a/.github/workflows/playwright-production.yml b/.github/workflows/playwright-production.yml new file mode 100644 index 0000000..d40e247 --- /dev/null +++ b/.github/workflows/playwright-production.yml @@ -0,0 +1,91 @@ +# 正式服(huiwings)E2E 联通性验收 +# 仅手动触发 + 每日定时,不跟随 push/PR 自动执行。 +name: production Smoke + +on: + workflow_dispatch: + inputs: + base_url: + description: H5 基址 + required: false + default: "https://music-room.huiwings.cn" + type: string + kc_base_url: + description: htykc 反代基址 + required: false + default: "https://admin.huiwings.cn" + type: string + prod_org_id: + description: 正式服机构 ID + required: false + default: "b79d09b0-0b65-44fb-936c-dcebf01097ba" + type: string + schedule: + # 每天 05:00 UTC(北京时间 13:00)跑一次 + - cron: "0 5 * * *" + +concurrency: + group: huike-e2e-production-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + smoke: + runs-on: ubuntu-latest + timeout-minutes: 15 + permissions: + contents: read + steps: + - uses: actions/checkout@v4 + + - name: 解析环境变量 + run: | + BASE="${{ inputs.base_url }}" + KC="${{ inputs.kc_base_url }}" + ORG="${{ inputs.prod_org_id }}" + echo "HUIKE_FRONT_BASE_URL=${BASE:-https://music-room.huiwings.cn}" >> "$GITHUB_ENV" + echo "KC_BASE_URL=${KC:-https://admin.huiwings.cn}" >> "$GITHUB_ENV" + echo "PROD_ORG_ID=${ORG:-b79d09b0-0b65-44fb-936c-dcebf01097ba}" >> "$GITHUB_ENV" + echo "Using BASE=$BASE KC=$KC ORG=$ORG" + + - uses: actions/setup-node@v4 + with: + node-version: "20" + cache: "npm" + cache-dependency-path: package-lock.json + + - name: 依赖与 Chromium + run: | + npm ci + npx playwright install chromium --with-deps + + - name: Playwright — 基础联通性与访客测试 + run: | + npx playwright test \ + tests/smoke-http.spec.ts \ + tests/guest-onboarding.spec.ts \ + tests/home-shell.spec.ts \ + tests/course-package-store.spec.ts \ + --grep-invert "已登录|权限与预览" + + - name: 正式服 SSH 只读校验(若已配置密钥) + env: + PROD_SSH_HOST: alchemy-studio.cn + SSH_USER: ${{ secrets.PROD_SSH_USER }} + SSH_KEY: ${{ secrets.PROD_SSH_PRIVATE_KEY }} + SSH_KNOWN_HOSTS: ${{ secrets.PROD_SSH_KNOWN_HOSTS }} + run: | + if [ -z "$SSH_USER" ] || [ -z "$SSH_KEY" ]; then + echo "PROD_SSH_USER / PROD_SSH_PRIVATE_KEY 未配置,跳过 SSH 校验" + exit 0 + fi + set -euo pipefail + mkdir -p ~/.ssh + chmod 700 ~/.ssh + printf '%s\n' "$SSH_KNOWN_HOSTS" >> ~/.ssh/known_hosts + printf '%s\n' "$SSH_KEY" > ~/.ssh/prod_ci + chmod 600 ~/.ssh/prod_ci + ssh -i ~/.ssh/prod_ci \ + -o StrictHostKeyChecking=yes \ + -o IdentitiesOnly=yes \ + "${SSH_USER}@${PROD_SSH_HOST}" \ + 'bash -s' < scripts/production-remote-check.sh diff --git a/scripts/production-remote-check.sh b/scripts/production-remote-check.sh new file mode 100644 index 0000000..8e43ec7 --- /dev/null +++ b/scripts/production-remote-check.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# 正式服只读健康检查 +# 由 GitHub Actions(playwright-production.yml)通过 SSH 调用 + +set -euo pipefail + +echo "=== htykc ===" +if ps aux | grep -q '[h]tykc'; then + echo "htykc: RUNNING" + ps aux | grep '[h]tykc' | awk '{print $2, $8, $11}' +else + echo "htykc: NOT RUNNING" + exit 1 +fi + +echo "" +echo "=== htyproc ===" +if ps aux | grep -q '[h]typroc'; then + echo "htyproc: RUNNING" +else + echo "htyproc: NOT RUNNING (optional)" +fi + +echo "" +echo "=== nginx ===" +nginx -t 2>&1 || sudo nginx -t 2>&1 + +echo "" +echo "=== disk ===" +df -h / | tail -1 + +echo "" +echo "=== load ===" +uptime + +echo "" +echo "=== memory ===" +free -h | grep -v Swap + +echo "" +echo "=== ALL CHECKS PASSED ===" diff --git a/tests/smoke-http.spec.ts b/tests/smoke-http.spec.ts index bf91ae4..ad08884 100644 --- a/tests/smoke-http.spec.ts +++ b/tests/smoke-http.spec.ts @@ -10,7 +10,7 @@ function frontBaseUrl(): string { /** * 不依赖浏览器:验证网关返回 H5 入口文档(部署/ DNS / TLS / Nginx 全链路底线)。 */ -const testOrgId = '57753e11dff343b1ab95623933e8960b'; +const testOrgId = process.env.PROD_ORG_ID?.trim() || '57753e11dff343b1ab95623933e8960b'; test.describe('网关与 H5 文档(request)', () => { test('GET / 返回 HTML', async ({ request }) => {