mirror of
https://github.com/GSManagerXZ/GameServerManager.git
synced 2026-10-20 14:24:46 +08:00
ci: add pull request validation workflow
This commit is contained in:
24
.github/workflows/build.yml
vendored
24
.github/workflows/build.yml
vendored
@@ -80,12 +80,16 @@ jobs:
|
||||
with:
|
||||
node-version: '22.16.0'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: |
|
||||
package-lock.json
|
||||
client/package-lock.json
|
||||
server/package-lock.json
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
npm install
|
||||
cd client && npm install
|
||||
cd ../server && npm install
|
||||
npm ci
|
||||
npm ci --prefix client
|
||||
npm ci --prefix server
|
||||
- name: Build Linux ${{ matrix.arch }} package
|
||||
run: ${{ matrix.package_command }}
|
||||
env:
|
||||
@@ -111,15 +115,15 @@ jobs:
|
||||
with:
|
||||
node-version: '22.16.0'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: |
|
||||
package-lock.json
|
||||
client/package-lock.json
|
||||
server/package-lock.json
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
npm install
|
||||
cd client
|
||||
npm install
|
||||
cd ..
|
||||
cd server
|
||||
npm install
|
||||
cd ..
|
||||
npm ci
|
||||
npm ci --prefix client
|
||||
npm ci --prefix server
|
||||
- name: Build package
|
||||
run: npm run package:windows
|
||||
env:
|
||||
|
||||
106
.github/workflows/ci.yml
vendored
Normal file
106
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
- reopened
|
||||
- ready_for_review
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
CI: true
|
||||
NODE_VERSION: '22.16.0'
|
||||
|
||||
jobs:
|
||||
server:
|
||||
name: Server test and build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
cache: npm
|
||||
cache-dependency-path: server/package-lock.json
|
||||
|
||||
- name: Install server dependencies
|
||||
run: npm ci
|
||||
working-directory: server
|
||||
|
||||
- name: Run server tests
|
||||
run: npm test
|
||||
working-directory: server
|
||||
|
||||
- name: Build server
|
||||
run: npm run build
|
||||
working-directory: server
|
||||
|
||||
client:
|
||||
name: Client test and build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
cache: npm
|
||||
cache-dependency-path: client/package-lock.json
|
||||
|
||||
- name: Install client dependencies
|
||||
run: npm ci
|
||||
working-directory: client
|
||||
|
||||
- name: Run client tests
|
||||
run: npm test
|
||||
working-directory: client
|
||||
|
||||
- name: Build client
|
||||
run: npm run build
|
||||
working-directory: client
|
||||
|
||||
project-scripts:
|
||||
name: Project scripts
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
cache: npm
|
||||
cache-dependency-path: package-lock.json
|
||||
|
||||
- name: Install root dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Check packaging scripts syntax
|
||||
run: |
|
||||
node --check scripts/package.js
|
||||
node --check scripts/resolve-build-version.js
|
||||
|
||||
- name: Resolve build version
|
||||
run: node scripts/resolve-build-version.js
|
||||
@@ -88,6 +88,18 @@ async function waitFor(condition: () => boolean, timeoutMs = 5000): Promise<void
|
||||
/** 完成所有 XHR 并结束上传流程 */
|
||||
async function cleanupUpload(uploadPromise: Promise<void>, chunkSize: number): Promise<void> {
|
||||
try {
|
||||
;(globalThis.fetch as any).mockImplementation(async (url: string, options?: any) => {
|
||||
if (options?.body) {
|
||||
try {
|
||||
const body = JSON.parse(options.body)
|
||||
if (body.uploadId !== undefined && body.totalChunks !== undefined && !body.chunkIndex && body.targetPath) {
|
||||
return { ok: true, json: async () => ({ success: true }) }
|
||||
}
|
||||
} catch { /* 非 JSON body */ }
|
||||
}
|
||||
return { ok: true, json: async () => ({ uploadedChunks: [] }) }
|
||||
})
|
||||
|
||||
// 多轮完成,处理批次间的延迟和新 XHR 创建
|
||||
for (let round = 0; round < 5; round++) {
|
||||
for (const xhr of xhrInstances) {
|
||||
@@ -98,11 +110,6 @@ async function cleanupUpload(uploadPromise: Promise<void>, chunkSize: number): P
|
||||
}
|
||||
await new Promise(r => setTimeout(r, 300))
|
||||
}
|
||||
// Mock merge
|
||||
;(globalThis.fetch as any).mockResolvedValue({
|
||||
ok: true,
|
||||
json: async () => ({ success: true }),
|
||||
})
|
||||
await Promise.race([
|
||||
uploadPromise,
|
||||
new Promise((_, rej) => setTimeout(() => rej(new Error('清理超时')), 8000)),
|
||||
|
||||
@@ -419,11 +419,14 @@ describe('保持行为属性测试 — 非进度计算行为不变', () => {
|
||||
it('属性4: abort 信号正确中止所有 XHR 请求', async () => {
|
||||
const FILE_SIZE = 200 * MB
|
||||
const controller = new AbortController()
|
||||
const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
||||
|
||||
const file = createMockFile(FILE_SIZE)
|
||||
const uploader = new ChunkUploader({
|
||||
file,
|
||||
targetPath: '/test',
|
||||
maxRetries: 1,
|
||||
signal: controller.signal,
|
||||
})
|
||||
|
||||
@@ -450,6 +453,10 @@ describe('保持行为属性测试 — 非进度计算行为不变', () => {
|
||||
// 验证 XHR 实例的 abort 被调用
|
||||
const abortedCount = xhrBeforeAbort.filter(xhr => xhr._aborted).length
|
||||
expect(abortedCount).toBe(CONCURRENT_UPLOADS)
|
||||
|
||||
await uploadPromise
|
||||
consoleWarnSpy.mockRestore()
|
||||
consoleErrorSpy.mockRestore()
|
||||
})
|
||||
|
||||
// ============================================================
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
export interface ChunkUploadOptions {
|
||||
file: File
|
||||
targetPath: string
|
||||
chunkSize?: number // 默认50MB
|
||||
chunkSize?: number // 默认20MB
|
||||
maxRetries?: number // 单个分片最大重试次数
|
||||
onProgress?: (progress: number) => void
|
||||
onChunkProgress?: (chunkIndex: number, totalChunks: number, chunkProgress: number) => void
|
||||
|
||||
@@ -2,11 +2,28 @@
|
||||
|
||||
## 概述
|
||||
|
||||
项目现已支持通过GitHub Actions自动构建多架构Docker镜像,包括AMD64和ARM64平台。
|
||||
项目通过 GitHub Actions 分离常规 CI 与发布构建:
|
||||
|
||||
- `ci.yml`:PR / `main` 分支常规检查,运行服务端测试与构建、前端测试与构建、根级脚本语法检查。
|
||||
- `build.yml`:发布构建,支持 Linux / Windows 应用包和 Docker 镜像。
|
||||
|
||||
## 可用的构建选项
|
||||
|
||||
### 1. 主构建工作流 (build.yml)
|
||||
### 1. 常规 CI 工作流 (ci.yml)
|
||||
|
||||
#### 自动触发:
|
||||
- PR 打开、重新打开、推送新提交或从 Draft 标记为可审阅
|
||||
- 推送到 `main` 分支
|
||||
|
||||
#### 手动触发:
|
||||
- 支持 `workflow_dispatch`
|
||||
|
||||
#### 检查内容:
|
||||
- 服务端:`npm ci`、`npm test`、`npm run build`
|
||||
- 前端:`npm ci`、`npm test`、`npm run build`
|
||||
- 根级脚本:`npm ci`、`node --check scripts/package.js`、`node --check scripts/resolve-build-version.js`
|
||||
|
||||
### 2. 发布构建工作流 (build.yml)
|
||||
|
||||
#### 手动触发选项:
|
||||
- ✅ **构建Linux版本** - 构建Linux应用包
|
||||
@@ -23,22 +40,15 @@
|
||||
> 导致同一版本启动两次构建、并发推送同一 Docker 标签互相冲突。
|
||||
> 详见 [Release重复触发CI修复说明.md](./Release重复触发CI修复说明.md)。
|
||||
|
||||
### 2. 专用多架构工作流 (docker-multiarch.yml)
|
||||
|
||||
提供更详细的多架构构建控制:
|
||||
- 可选择构建平台组合
|
||||
- 支持自定义镜像标签
|
||||
- 包含架构验证测试
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 方法一:GitHub网页操作
|
||||
|
||||
1. 进入GitHub仓库页面
|
||||
2. 点击 **Actions** 标签
|
||||
3. 选择 **Build Package** 工作流
|
||||
3. 选择 **Build Package** 工作流进行发布构建,或选择 **CI** 手动运行常规检查
|
||||
4. 点击 **Run workflow**
|
||||
5. 选择需要的构建选项:
|
||||
5. 如果运行 **Build Package**,选择需要的构建选项:
|
||||
- ☑️ 构建ARM64 Docker镜像
|
||||
- ☑️ 构建Docker镜像(多架构)
|
||||
6. 点击 **Run workflow** 开始构建
|
||||
@@ -64,8 +74,8 @@ gh workflow run build.yml -f build_docker=true
|
||||
# 触发所有构建
|
||||
gh workflow run build.yml -f build_linux=true -f build_windows=true -f build_docker=true -f build_docker_arm=true
|
||||
|
||||
# 使用专用多架构工作流
|
||||
gh workflow run docker-multiarch.yml -f tag=latest -f platforms="linux/amd64,linux/arm64" -f push_to_registry=true
|
||||
# 手动触发常规 CI
|
||||
gh workflow run ci.yml
|
||||
```
|
||||
|
||||
## 构建产物
|
||||
@@ -138,7 +148,7 @@ docker run --platform linux/amd64 --rm xiaozhu674/gameservermanager:latest uname
|
||||
1. **开发阶段**:使用ARM64专用构建进行快速测试
|
||||
2. **发布阶段**:使用多架构构建确保兼容性
|
||||
3. **标签管理**:为不同版本使用语义化版本标签
|
||||
4. **缓存优化**:GitHub Actions会自动缓存构建层以加速后续构建
|
||||
4. **缓存优化**:GitHub Actions 会缓存 npm 下载缓存和 Docker 构建层以加速后续构建
|
||||
|
||||
## 更新日志
|
||||
|
||||
@@ -146,3 +156,4 @@ docker run --platform linux/amd64 --rm xiaozhu674/gameservermanager:latest uname
|
||||
- **v1.1**: 支持多架构并行构建
|
||||
- **v1.2**: 添加构建验证和测试步骤
|
||||
- **v1.3**: 移除 release 事件触发器,修复发布 Release 时重复启动两次构建的问题
|
||||
- **v1.4**: 新增 PR/main 常规 CI,并将发布构建依赖安装改为 `npm ci`
|
||||
|
||||
@@ -1,30 +1,39 @@
|
||||
# PR 自动语法检查说明
|
||||
# PR 自动检查说明
|
||||
|
||||
## 说明
|
||||
|
||||
`pr-auto-check.yml` 现在只负责对 PR 进行代码语法检查,不再执行以下操作:
|
||||
`.github/workflows/ci.yml` 负责 PR 和 `main` 分支的常规持续集成检查。该流程只做只读校验,不评论 PR、不自动合并,也不修改目标分支。
|
||||
|
||||
- 自动切换 PR 的目标分支
|
||||
- 自动合并 PR
|
||||
- 自动创建或调整 `feature` 分支
|
||||
发布构建仍由 `.github/workflows/build.yml` 负责,避免把 PR 校验和 Release 打包推送混在一起。
|
||||
|
||||
## 触发时机
|
||||
|
||||
- PR 打开、重新打开、推送新提交或从 Draft 标记为可审阅时触发。
|
||||
- 推送到 `main` 分支时触发。
|
||||
- 维护者也可以通过 `workflow_dispatch` 手动触发。
|
||||
|
||||
同一 PR 或同一分支的旧运行会被自动取消,减少重复排队。
|
||||
|
||||
## 检查范围
|
||||
|
||||
当前流程会在 PR 打开、重新打开、推送新提交或标记为可审阅时触发,并执行以下内容:
|
||||
当前 CI 包含三个 job:
|
||||
|
||||
1. 读取 PR 变更文件列表,并在评论中提示当前状态
|
||||
2. 检出 PR 对应提交
|
||||
3. 判断是否仅包含文档变更
|
||||
4. 对 `server` 和 `client` 分别执行 `npx tsc --noEmit`
|
||||
5. 如果检查失败,在 PR 中回复中文错误信息
|
||||
|
||||
## 结果说明
|
||||
|
||||
- 如果 PR 仅修改文档或文本文件,会跳过代码语法检查,并在 PR 中给出提示
|
||||
- 如果 `server` 或 `client` 的 TypeScript 检查失败,工作流会返回对应的错误输出
|
||||
- 如果检查通过,工作流不会再自动合并代码,也不会修改 PR 的目标分支
|
||||
1. `Server test and build`
|
||||
- `cd server && npm ci`
|
||||
- `cd server && npm test`
|
||||
- `cd server && npm run build`
|
||||
2. `Client test and build`
|
||||
- `cd client && npm ci`
|
||||
- `cd client && npm test`
|
||||
- `cd client && npm run build`
|
||||
3. `Project scripts`
|
||||
- `npm ci`
|
||||
- `node --check scripts/package.js`
|
||||
- `node --check scripts/resolve-build-version.js`
|
||||
- `node scripts/resolve-build-version.js`
|
||||
|
||||
## 维护建议
|
||||
|
||||
- 如果后续希望增加其他静态检查,可以在这里继续补充流程说明
|
||||
- 如果需要恢复自动合并,请单独设计新的工作流,不建议和语法检查混在一起
|
||||
- CI 中优先使用 `npm ci`,确保 lockfile 和实际安装一致。
|
||||
- 新增必须通过的检查前,先确认当前 `upstream/main` 基线能稳定通过。
|
||||
- Release 打包、Docker 推送和上传 GitHub Release 资产应继续放在 `build.yml`,并只在标签推送或手动触发时执行。
|
||||
|
||||
Reference in New Issue
Block a user