@daiyu-5577/buildsystem
v1.3.1
Published
CLI tool to build projects based on git changes
Readme
BuildSystem
基于 Git 变更的自动化构建系统,提供 CLI 构建命令和 Web 可视化构建管理界面,支持增量构建、并发控制、实时消息推送、版本回退、Webhook 通知和多用户权限管理。
功能概览
- CLI 构建 — 命令行一键触发构建,支持指定分支、目录、commit 区间
- Web 管理界面 — 实时构建状态监控、聊天室、日志查看、版本回退、用户权限管理
- 增量构建 — 通过
git diff识别变更项目,仅构建受影响的包 - 并发控制 — 可配置最大并发构建数(
MAX_CONCURRENCY) - 实时推送 — Socket.IO 双向通信,构建日志实时流式推送
- Webhook 通知 — 构建完成自动通知外部系统
- 版本回退 — 构建前自动备份,支持一键回退
- 定时清理 — Cron 定时清理旧日志和备份
- 多用户认证 — Token 加密鉴权,支持邀请注册
- 角色权限 — 三级角色体系(Super / Admin / User),细粒度权限控制
目录结构
buildSystem/
├── src/ # 后端(Node.js + TypeScript + ESM)
│ ├── cli.ts # CLI 入口(commander)
│ ├── commands/
│ │ ├── build.ts # build 命令:纯 CLI 构建
│ │ └── server.ts # server 命令:启动 Web 服务
│ ├── server/
│ │ ├── index.ts # Express + Socket.IO 服务主类
│ │ ├── routes.ts # REST API 路由(含用户管理接口)
│ │ └── websocket.ts # WebSocket 处理器 & 命令系统
│ ├── queue.ts # 构建任务队列(并发控制、增量构建)
│ ├── git.ts # Git 异步操作(checkout/pull/diff/clean)
│ ├── pm.ts # 包管理器检测(npm/yarn/pnpm)
│ ├── artifact.ts # 构建产物备份与复制
│ ├── notifier.ts # 通知系统(Socket.IO + Webhook)
│ ├── cron.ts # Cron 定时任务
│ ├── crypto.ts # AES-256-CBC 加解密
│ ├── database/
│ │ ├── index.ts # JSON 文件数据库
│ │ └── types.ts # 数据库类型(User/Message/Invite)
│ ├── config.ts # 集中配置(环境变量 + 路径)
│ ├── types.ts # 公共类型定义
│ ├── logger.ts # Winston 日志(http / socket 分离)
│ ├── fsHelpers.ts # 文件系统工具
│ ├── utils.ts # 通用工具函数
│ └── custError.ts # 自定义错误
│
├── web/ # 前端(React + Vite + Less)
│ ├── src/
│ │ ├── main.tsx # 入口(Router + AuthGuard)
│ │ ├── pages/
│ │ │ ├── Home.tsx # 主页(构建面板 + 聊天室 + 用户操作)
│ │ │ ├── Login.tsx # 登录/注册页
│ │ │ ├── InviteModal.tsx # 邀请码弹窗
│ │ │ ├── PermissionModal.tsx # 权限管理弹窗
│ │ │ ├── UserInfoModal.tsx # 用户信息弹窗
│ │ │ └── *.module.less # 页面级样式
│ │ ├── components/
│ │ │ ├── Modal/ # 模态框体系(StackModal/Toast/Confirm/ImagePreview)
│ │ │ ├── Select/ # 下拉选择器
│ │ │ ├── SuggestMenu/ # 命令建议菜单
│ │ │ └── UserAvatar/ # 用户头像下拉组件
│ │ ├── hooks/
│ │ │ ├── useSocket.ts # Socket.IO 连接 + 消息管理
│ │ │ └── useScrollToBottom.ts
│ │ ├── utils/
│ │ │ └── api.ts # API 封装(带 token)
│ │ └── index.css # 全局样式 & CSS 变量
│ └── vite.config.ts
│
├── .buildsystemCatch/ # 运行时缓存(自动创建)
│ ├── webBackup/ # 构建产物备份
│ ├── buildLog/ # 构建日志
│ ├── database/ # JSON 数据库
│ ├── log/ # HTTP 日志
│ └── images/ # 聊天图片
│
├── .env.example # 环境变量模板
├── package.json
└── tsconfig.json架构
┌──────────────────────────────────────────────────────────────┐
│ Browser │
│ ┌──────────┐ ┌──────────┐ ┌───────────────────────────┐ │
│ │ Login │ │ Home │ │ Modal/Select/UserAvatar │ │
│ │ (React) │ │ (React) │ │ (React Components) │ │
│ └────┬─────┘ └────┬─────┘ └─────────────┬─────────────┘ │
│ │ │ │ │
│ └──────┬───────┴───────────────────────┘ │
│ │ REST API + Socket.IO │
└──────────────┼────────────────────────────────────────────────┘
│
┌──────────────┼────────────────────────────────────────────────┐
│ BuildServer (Express) │
│ ┌───────────┴───────────┐ │
│ │ routes.ts (REST API) │ websocket.ts (Socket.IO) │
│ │ - 构建任务管理 │ - 实时消息推送 │
│ │ - 用户与权限管理 │ - 聊天室 & 快捷命令 │
│ │ - 邀请码管理 │ - 构建日志订阅 │
│ └───────────┬───────────┘──────────┬─────────────────────────┘
│ │ │ │
│ ┌───────────┴───────────────────────┴────────────────────────┐ │
│ │ BuildTaskQueue │ │
│ │ ┌─────────┐ ┌──────────┐ ┌───────────────────────────┐ │ │
│ │ │ git.ts │ │ pm.ts │ │ artifact.ts │ │ │
│ │ │ checkout │ │ npm ci │ │ backup / copy / restore │ │ │
│ │ │ pull │ │ yarn │ │ │ │ │
│ │ │ diff │ │ pnpm │ └───────────────────────────┘ │ │
│ │ └─────────┘ └──────────┘ │ │
│ └───────────────────────────────────────────────────────────┘ │
│ ┌─────────────┐ ┌───────────┐ ┌──────────────────────────┐ │
│ │ notifier.ts │ │ cron.ts │ │ database/ │ │
│ │ webhook │ │ 定时清理 │ │ User / Message / Invite │ │
│ └─────────────┘ └───────────┘ └──────────────────────────┘ │
└────────────────────────────────────────────────────────────────┘快速开始
前置要求
- Node.js >= 16
- 项目根目录包含
package.json(含build脚本)
使用方式
buildSystem 支持两种使用场景:作为全局 CLI 工具直接使用,或从源码开发。
全局安装
npm install @daiyu-5577/buildsystem -g# 构建项目,指定分支为 master
buildsystem build -b master
# 启动 Web 服务
# 启动后访问 `http://localhost:3000/buildsystem` 进入后台 Web 界面
# 账号/密码:root/123456
buildsystem server --port 3000
# 启动 Web 服务,并托管网站。静态文件根路径为 /path/to/dist,网站路由前缀为 /page
# 启动后访问 `http://localhost:3000/page/app` 进入静态托管的 Web 界面
buildsystem server --port 3000 --website /path/to/dist --website-prefix /pageCLI 命令参考
build 命令 — 纯 CLI 构建,不启动 Web 服务
buildsystem build -b <branch> [-p <paths...>] [-c <commit>] [-n <notify>]| 参数 | 说明 | 示例 |
|------|------|------|
| -b, --branch | 目标分支(必填) | master |
| -p, --packagePaths | 指定构建目录 | packages/app1 packages/app2 |
| -c, --commit | commit 区间,增量构建 | abc123..def456 |
| -n, --notify | 构建通知地址 | https://hooks.example.com/notify |
server 命令 — 启动 Web 管理界面 + REST API + Socket.IO
buildsystem server [--port <number>] [--website <path>] [--website-prefix <prefix>]| 参数 | 说明 | 默认值 |
|------|------|--------|
| --port | 端口号 | 3000 |
| --website | 托管的网站静态文件路径 | 空 |
| --website-prefix | 网站路由前缀(挂载点) | /page |
Nginx 反向代理配置
当自定义了 BASE_ROUTE 环境变量,并通过nginx匹配该路径location BASE_ROUTE,需要通过反向代理将所有匹配的路径统一转发到后端服务:
server {
listen 80;
server_name example.com;
# 匹配自定义 BASE_ROUTE 路径下的所有请求,全部转发到后端
location /$BASE_ROUTE/ {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# 匹配 /buildsystem 路径下的所有请求,全部转发到后端
# 启动后访问 `http://localhost:3000/buildsystem` 进入后台 Web 界面
location /buildsystem/ {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}如果使用 --website-prefix /page 托管另一个站点,则需添加对应的 location block:
location /page/ {
proxy_pass http://127.0.0.1:3000;
# ... 同上 header
}这样无论前端如何路由,所有请求都会到达 Express,由 findIndexHtml 或 express.static 正确处理 SPA 的 fallback 逻辑。
网站托管(--website / --website-prefix)
通过 server --website <path> --website-prefix <prefix> 可在指定 URL 路径下托管任意静态网站:
buildsystem server \
--website /data/sites/app \
--website-prefix /app| 参数 | 作用 | 示例 |
|------|------|------|
| --website | 静态文件实际所在的绝对路径 | /data/sites/app |
| --website-prefix | URL 匹配前缀(挂载点) | /app |
访问 http://example.com/app → 返回 /data/sites/app/index.html
访问 http://example.com/app/login → 返回 /data/sites/app/login/index.html
多层级目录结构
假设 website-root 目录如下:
/data/sites/app/
├── index.html # /app → 命中
├── login/index.html # /app/login → 命中
├── vue/index.html # /app/vue → 命中
│ └── assets/
└── react/index.html # /app/react → 命中
└── assets/只需启动一次服务,所有子路径自动生效。无需为每个站点单独配置 --website-path。
| 客户端访问 | 查找逻辑 | 结果 |
|-----------|---------|------|
| /app | /data/sites/app/index.html | ✅ |
| /app/login | /data/sites/app/login/index.html | ✅ |
| /app/vue/assets/logo.png | express.static 直接提供静态资源 | ✅ |
| /app/vue/non-existent | 逐级 fallback 查找 index.html | 找到最近的父级或根 |
findIndexHtml 逐级查找算法
当请求无文件扩展名(SPA History 模式)时,服务端从长到短逐级尝试匹配:
请求路径: /app/vue/deep/page
匹配路径: /app
websiteRoot: /data/sites/app
1. /data/sites/app + /vue/deep/page + /index.html → 不存在
2. /vue/deep + /index.html → 不存在
3. /vue + /index.html → ✅ 命中--website-prefix仅作为 Express 的use前缀过滤,不参与最终文件路径拼接- 拼接公式:
websiteRoot + 请求路径的前缀 + /index.html - 逐级向上 fallback 直到根目录的
index.html
注意事项
| 要点 | 说明 |
|------|------|
| 位置顺序 | location 按前缀匹配优先级从高到低排列,较长前缀应放在较之前,否则短前缀会先匹配拦截请求 |
| /buildsystem/ | 这是前端 Vite 构建产物所在的路径,对应代码中 base: '/buildsystem' |
| /app/vue/、/app/react/ | 通过 server --website-prefix /app 启动后,所有 /app/** 请求都会被 Express 代理处理 |
| WebSocket 头 | Socket.IO 依赖 Upgrade + Connection 头部做协议升级,务必添加这两行 |
Vite 配置详解
前端使用 Vite 6 开发,配置文件位于 web/vite.config.ts:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
base: '/buildsystem', // ① 前端资源路径前缀,与 Nginx 的 location 和 Express 的静态文件路径对应
plugins: [react()], // ② React JSX 转换插件
server: {
port: 5173, // ③ 开发服务器端口
proxy: { // ④ 开发环境代理:将 /api、/ws 请求转发到后端 :3000
'/api': { // - /api → Express REST API(用户认证、任务管理等)
target: 'http://localhost:3000',
changeOrigin: true, // - 修改 Host 头为目标地址,避免 CORS 问题
},
'/ws': { // - /ws → Socket.IO 实时通信端点
target: 'http://localhost:3000',
ws: true, // - 启用 WebSocket 代理
},
},
},
build: {
outDir: '../dist/web', // ⑤ 生产构建输出目录(相对于 web/ 即项目根目录的 dist/web)
emptyOutDir: true, // ⑥ 构建前先清空输出目录,避免残留旧文件
},
})| 字段 | 作用 | 注意事项 |
|------|------|----------|
| base | 定义前端资源(JS/CSS/HTML)访问路径的前缀 | 设为 /buildsystem 表示所有请求 URL 以 /buildsystem/ 开头;若改为 / 则表示直接部署在域名根路径下 |
| server.proxy | 仅开发环境生效,解决前后端同源策略 | 生产环境需通过 Nginx 反向代理或后端统一端口解决 |
| build.outDir | 指定编译产出放置位置 | 默认会覆盖整个目录,配合 emptyOutDir 保证干净构建 |
| build.emptyOutDir | 确保每次构建都是全新产物 | 如果希望保留某些文件可设为 false,但通常建议开启 |
环境变量
| 变量 | 说明 | 默认值 |
|------|------|--------|
| NODE_ENV | 运行环境 | development |
| BASE_ROUTE | REST API 路由前缀(即 express 中 /api/... 的前缀) | 空 |
| CATCH_ROOT | 缓存根目录 | .buildsystemCatch |
| DIST_ROOT | 构建产物目录 | dist |
| MAX_CONCURRENCY | 最大并发构建数 | 1 |
| CRYPTO_SALT | AES 加密 salt | 生产环境必须设置 |
| CRYPTO_SECRET | AES 加密 secret | 生产环境必须设置 |
| WEBHOOK_URL | Webhook 通知地址 | 空 |
用户权限体系
系统采用三级角色体系:
| 角色 | 权限 | |------|------| | Super | 全部权限:可以分配 Super/Admin/User 角色、生成邀请码 | | Admin | 管理权限:可以分配 Admin/User 角色、查看所有构建 | | User | 普通用户:仅可查看构建状态、发送聊天消息 |
邀请注册流程
- 管理员(Super/Admin)生成邀请码
- 将邀请码分享给新用户
- 用户在登录页切换至"注册"Tab,输入用户名、密码和邀请码完成注册
权限管理
- 点击右上角头像打开下拉菜单,选择"权限管理"(需 Admin 或以上角色)
- 搜索用户后通过下拉框修改其角色
- Admin 不能降级或提升 Super 角色的用户
API
启动 Server 后,主要接口位于 /api/ 路径下(若设置了 BASE_ROUTE,则为 <BASE_ROUTE>/api/...):
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | /api/login | 用户登录 |
| POST | /api/register | 用户注册(需邀请码) |
| POST | /api/addTask | 添加构建任务 |
| POST | /api/cancelTask | 取消构建任务 |
| GET | /api/getAllTask | 获取任务列表 |
| GET | /api/getAllPackage | 获取可构建项目列表 |
| GET | /api/refreshPackages | 刷新可构建项目列表(Admin/Super) |
| GET | /api/getAllLog | 获取日志列表 |
| GET | /api/getAllBackup | 获取备份列表 |
| POST | /api/restore | 版本回退 |
| GET | /api/getNoticeList | 获取通知配置 |
| POST | /api/notify | Webhook 回调(构建通知) |
| GET | /api/getUserInfo | 获取当前/指定用户信息 |
| GET | /api/getAllUsers | 获取所有用户列表(Admin/Super) |
| POST | /api/updateUserRole | 更新用户角色(Admin/Super) |
| GET | /api/inviteCodes | 获取当前用户的邀请码列表(Super) |
| POST | /api/generateInviteCode | 生成新邀请码(Super) |
构建流程
添加任务 → 入队列 → 并发调度 → 执行:
1. git checkout <branch> + git pull
2. 检测包管理器 → npm ci / yarn install / pnpm install
3. npm run build
4. 备份旧产物 → 复制新产物到 dist/
5. git clean(还原工作区)
→ 成功/失败 → Webhook 通知 + Socket.IO 推送技术栈
后端:Node.js · TypeScript · ESM · Express 5 · Socket.IO · Commander · Winston · dayjs · fs-extra
前端:React 19 · Vite 6 · TypeScript · React Router 6 · Socket.IO Client · Less (CSS Modules)
License
MIT
