diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml new file mode 100644 index 0000000..ff35a7a --- /dev/null +++ b/.forgejo/workflows/ci.yml @@ -0,0 +1,54 @@ +name: CI + +on: + push: + branches: + - main + pull_request: + +permissions: + contents: read + +jobs: + quality: + name: Node 质量门禁 + runs-on: docker + timeout-minutes: 15 + steps: + - name: 检出代码 + uses: actions/checkout@v4 + - name: 配置 Node.js + uses: actions/setup-node@v4 + with: + node-version: 22.18.0 + cache: npm + - name: 安装锁定依赖 + run: npm ci + - name: TypeScript 类型检查 + run: npm run typecheck + - name: 单元与组件测试 + run: npm test + - name: 生产构建 + run: npm run build + - name: 高危依赖审计 + run: npm audit --audit-level=high + + docker: + name: Docker 构建与健康检查 + runs-on: docker + timeout-minutes: 15 + steps: + - name: 检出代码 + uses: actions/checkout@v4 + - name: 构建 Web 镜像 + run: docker compose build web + - name: 启动 Web 服务 + run: docker compose up --no-build --detach web + - name: 等待健康检查通过 + run: ./scripts/check-web-health.sh + - name: 输出故障诊断 + if: failure() + run: docker compose ps && docker compose logs --no-color web + - name: 清理容器 + if: always() + run: docker compose down --volumes --remove-orphans diff --git a/README.md b/README.md index 31089d9..c3df496 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,11 @@ npm run tauri dev # 桌面开发模式 无需本机 Node.js 的前端验证: ```bash +docker compose build test build docker compose run --rm test docker compose run --rm build +docker compose run --rm test npm run typecheck +docker compose run --rm test npm audit --audit-level=high ``` ## Docker 启动 Web 测试服务 @@ -38,6 +41,7 @@ docker compose up --build -d ```bash docker compose ps docker compose logs -f web +./scripts/check-web-health.sh ``` 停止服务: @@ -64,8 +68,33 @@ WEB_BIND_ADDRESS=0.0.0.0 WEB_PORT=1420 docker compose up --build -d ## 常用命令 ```bash +npm ci npm run typecheck npm test npm run build +npm audit --audit-level=high npm run tauri build ``` + +## 持续集成与本地复现 + +Forgejo 工作流 [`.forgejo/workflows/ci.yml`](.forgejo/workflows/ci.yml) 在推送到 `main` 和拉取请求时运行两个独立作业: + +- Node 质量门禁依次执行锁定依赖安装、TypeScript 类型检查、测试、生产构建和高危依赖审计。 +- Docker 门禁构建 `web` 镜像,按 Compose 的最小权限配置启动服务,并等待镜像内置健康检查通过。 + +本机装有 Node.js 22.18.0 时,可使用“常用命令”中的前五条命令逐步复现 Node 作业。仅安装 Docker 时,可完整复现 CI: + +```bash +docker compose build test build +docker compose run --rm test npm run typecheck +docker compose run --rm test +docker compose run --rm build +docker compose run --rm test npm audit --audit-level=high +docker compose build web +docker compose up --no-build -d web +./scripts/check-web-health.sh +docker compose down --volumes --remove-orphans +``` + +依赖审计会在发现高危或严重漏洞时失败;网络或软件源不可用同样视为审计失败,不静默跳过。Docker 服务仍以非 root 用户运行,并保留只读根文件系统与 `no-new-privileges` 限制。 diff --git a/scripts/check-web-health.sh b/scripts/check-web-health.sh new file mode 100755 index 0000000..7e62fee --- /dev/null +++ b/scripts/check-web-health.sh @@ -0,0 +1,32 @@ +#!/bin/sh +set -eu + +max_attempts="${WEB_HEALTH_ATTEMPTS:-30}" +attempt=1 + +while [ "$attempt" -le "$max_attempts" ]; do + container_id="$(docker compose ps --quiet web)" + if [ -z "$container_id" ]; then + echo "Web 容器未运行" >&2 + exit 1 + fi + + status="$(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}missing{{end}}' "$container_id")" + case "$status" in + healthy) + echo "Web 容器健康检查通过" + exit 0 + ;; + unhealthy|missing) + echo "Web 容器健康状态异常:$status" >&2 + exit 1 + ;; + esac + + echo "等待 Web 容器健康检查($attempt/$max_attempts,当前:$status)" + attempt=$((attempt + 1)) + sleep 2 +done + +echo "Web 容器未在预期时间内进入 healthy 状态" >&2 +exit 1