Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file removed .DS_Store
Binary file not shown.
84 changes: 81 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v7
with:
go-version: '1.25'
go-version: "1.25"
cache-dependency-path: server/go.sum

- name: Verify modules
Expand Down Expand Up @@ -54,6 +54,31 @@ jobs:
working-directory: server
run: go test ./... -v

backend-windows:
name: Go Test (Windows)
runs-on: windows-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v7

- name: Set up Go
uses: actions/setup-go@v7
with:
go-version: "1.25"
cache-dependency-path: server/go.sum

- name: Verify modules
working-directory: server
run: go mod verify

- name: Build
working-directory: server
run: go build ./...

- name: Test
working-directory: server
run: go test ./...

frontend:
name: React Build & Test
runs-on: ubuntu-latest
Expand All @@ -64,18 +89,71 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@v7
with:
node-version: '24'
cache: 'npm'
node-version: "24"
cache: "npm"
cache-dependency-path: web/package-lock.json

- name: Install dependencies
working-directory: web
run: npm ci

- name: Audit production dependencies
working-directory: web
run: npm audit --omit=dev --audit-level=high

- name: Lint and formatting
working-directory: web
run: npm run lint && npm run format:check

- name: Test
working-directory: web
run: npm run test

- name: Type Check & Build
working-directory: web
run: npm run build

docs:
name: Documentation Build
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v7

- name: Set up Node.js
uses: actions/setup-node@v7
with:
node-version: "24"
cache: "npm"
cache-dependency-path: docs-site/package-lock.json

- name: Install dependencies
working-directory: docs-site
run: npm ci

- name: Type Check & Build
working-directory: docs-site
run: npm run typecheck && npm run build

container:
name: Container Build
needs: [backend, backend-windows, frontend, docs]
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v7

- name: Validate Compose configuration
run: docker compose config --quiet

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4

- name: Build image
uses: docker/build-push-action@v7
with:
context: .
push: false
tags: backupx:ci
cache-from: type=gha,scope=backupx-ci
cache-to: type=gha,mode=max,scope=backupx-ci
31 changes: 17 additions & 14 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ name: Release
on:
push:
tags:
- 'v*'
- "v*"
workflow_dispatch:
inputs:
version:
description: '版本号(如 v1.2.3)'
description: "版本号(如 v1.2.3)"
required: true
type: string

Expand Down Expand Up @@ -65,7 +65,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v7
with:
go-version: '1.25'
go-version: "1.25"
cache-dependency-path: server/go.sum

- name: Verify backend
Expand All @@ -83,14 +83,17 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@v7
with:
node-version: '24'
cache: 'npm'
node-version: "24"
cache: "npm"
cache-dependency-path: web/package-lock.json

- name: Verify frontend
working-directory: web
run: |
npm ci
npm audit --omit=dev --audit-level=high
npm run lint
npm run format:check
npm run test

# ─── Job 1: 构建前端 ───
Expand All @@ -105,8 +108,8 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@v7
with:
node-version: '24'
cache: 'npm'
node-version: "24"
cache: "npm"
cache-dependency-path: web/package-lock.json

- name: Install & Build
Expand Down Expand Up @@ -143,7 +146,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v7
with:
go-version: '1.25'
go-version: "1.25"
cache-dependency-path: server/go.sum

- name: Download frontend artifact
Expand All @@ -157,7 +160,7 @@ jobs:
env:
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
CGO_ENABLED: '0'
CGO_ENABLED: "0"
run: |
go build \
-trimpath \
Expand All @@ -172,13 +175,13 @@ jobs:
cp backupx "${ARCHIVE_NAME}/"
cp -r web/dist "${ARCHIVE_NAME}/web"
cp server/config.example.yaml "${ARCHIVE_NAME}/"
cp deploy/install.sh "${ARCHIVE_NAME}/" 2>/dev/null || true
cp deploy/backupx.service "${ARCHIVE_NAME}/" 2>/dev/null || true
cp deploy/install.sh "${ARCHIVE_NAME}/"
cp deploy/backupx.service "${ARCHIVE_NAME}/"
# v2.2+: 随发布包提供 Grafana dashboard 与 nginx.conf 模板
if [ -d deploy/grafana ]; then
cp -r deploy/grafana "${ARCHIVE_NAME}/grafana"
fi
cp deploy/nginx.conf "${ARCHIVE_NAME}/nginx.conf" 2>/dev/null || true
cp deploy/nginx.conf "${ARCHIVE_NAME}/nginx.conf"
tar czf "${ARCHIVE_NAME}.tar.gz" "${ARCHIVE_NAME}"
cp "${ARCHIVE_NAME}.tar.gz" "backupx-${{ matrix.goos }}-${{ matrix.goarch }}.tar.gz"
sha256sum "${ARCHIVE_NAME}.tar.gz" > "${ARCHIVE_NAME}.tar.gz.sha256"
Expand All @@ -199,7 +202,7 @@ jobs:
# ─── Job 3: Docker 多架构 → Docker Hub ───
build-docker:
name: Build & Push Docker
needs: build-web
needs: verify
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
Expand All @@ -226,7 +229,7 @@ jobs:
build-args: |
VERSION=${{ env.VERSION }}
tags: |
${{ secrets.DOCKERHUB_USERNAME }}/backupx:latest
${{ secrets.DOCKERHUB_USERNAME }}/backupx:${{ env.VERSION }}
${{ !contains(env.VERSION, '-') && format('{0}/backupx:latest', secrets.DOCKERHUB_USERNAME) || '' }}
cache-from: type=gha
cache-to: type=gha,mode=max
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ ARG USE_CHINA_MIRROR=false


# ---- Stage 1: Build frontend ----
FROM node:26-alpine AS web-builder
FROM node:24-alpine AS web-builder
ARG USE_CHINA_MIRROR

# 国内镜像:npm 使用淘宝源
Expand All @@ -26,7 +26,7 @@ RUN npm run build


# ---- Stage 2: Build backend ----
FROM golang:1.26-alpine AS server-builder
FROM golang:1.25-alpine AS server-builder
ARG USE_CHINA_MIRROR
ARG VERSION=dev

Expand Down
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ verify: verify-server verify-web verify-docs

verify-server: format-check vet-server test-server build-server

verify-web: test-web build-web
verify-web:
cd web && npm run lint && npm run format:check && npm run test && npm run build

verify-docs: check-docs

Expand Down
14 changes: 7 additions & 7 deletions docs-site/docs/development/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,17 @@ For significant features or refactors, open an issue first to align on scope bef
## Pull requests

1. Fork and create a topic branch (e.g. `fix/windows-path-escape`)
2. Run `make test` and make sure everything passes
2. Run `make verify` and make sure formatting, tests, builds, and documentation checks pass
3. Keep changes focused — one concern per PR
4. Write commit messages in Chinese following `类型: 简要描述` — examples:
- `功能: 新增审计日志模块`
- `修复: 目录浏览器无法进入子目录`
- `重构: 简化存储目标解密逻辑`
- Types: `功能` / `修复` / `重构` / `文档` / `构建` / `测试`
4. Write Conventional Commits with a Chinese subject — examples:
- `feat(audit): 新增审计日志模块`
- `fix(browser): 修复目录浏览器无法进入子目录`
- `refactor(storage): 简化存储目标解密逻辑`
- Types: `feat` / `fix` / `docs` / `style` / `refactor` / `perf` / `test` / `chore`
5. PR title and body in Chinese too. Describe the why and how, not just the what.

## Coding guidelines

- **Go** — handle every error (no `_ = err`); use the existing logger (`zap`); no `fmt.Println` in production paths
- **TypeScript** — strict mode, no implicit any, follow existing ESLint/Prettier configs
- **TypeScript** — strict mode, no implicit any, and pass the repository ESLint and Prettier checks
- **Commit scope** — one logical change per commit; don't mix drive-by cleanups with feature work
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,17 @@ BackupX 使用 Apache License 2.0 开源,欢迎提交 Issue 与 Pull Request
## 提交 PR

1. Fork 仓库,创建主题分支(如 `fix/windows-path-escape`)
2. 执行 `make test` 确认本地全通过
2. 执行 `make verify`,确认格式、测试、构建和文档检查全部通过
3. 保持每个 PR 只做一件事
4. Commit message 使用中文,格式 `类型: 简要描述`
- `功能: 新增审计日志模块`
- `修复: 目录浏览器无法进入子目录`
- `重构: 简化存储目标解密逻辑`
- 类型:`功能` / `修复` / `重构` / `文档` / `构建` / `测试`
4. Commit message 使用 Conventional Commits,主题使用中文
- `feat(audit): 新增审计日志模块`
- `fix(browser): 修复目录浏览器无法进入子目录`
- `refactor(storage): 简化存储目标解密逻辑`
- 类型:`feat` / `fix` / `docs` / `style` / `refactor` / `perf` / `test` / `chore`
5. PR 标题和正文同样使用中文,描述"为什么"和"怎么做",而非仅仅"做了什么"

## 代码规范

- **Go** — 所有错误必须处理(禁止 `_ = err`),日志使用现有 `zap`,禁止生产路径中出现 `fmt.Println`
- **TypeScript** — 严格模式,禁止隐式 any,遵循现有 ESLint/Prettier 配置
- **TypeScript** — 严格模式,禁止隐式 any,并通过仓库中的 ESLintPrettier 检查
- **Commit 粒度** — 每个 commit 一件事,不要把顺手的小修改和功能代码混在一起
Binary file removed server/.DS_Store
Binary file not shown.
11 changes: 3 additions & 8 deletions server/Makefile
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
APP_NAME=backupx
BUILD_DIR=./bin
VERSION=$(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")

.PHONY: build run test

build:
mkdir -p $(BUILD_DIR)
go build -trimpath -ldflags "-s -w -X main.version=$(VERSION)" -o $(BUILD_DIR)/$(APP_NAME) ./cmd/backupx
$(MAKE) -C .. build-server

run:
go run -ldflags "-X main.version=$(VERSION)" ./cmd/backupx
$(MAKE) -C .. dev-server

test:
go test ./...
$(MAKE) -C .. test-server
14 changes: 14 additions & 0 deletions server/cmd/backupx/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"syscall"

"backupx/server/internal/agent"
"backupx/server/internal/config"
applogger "backupx/server/internal/logger"
)

// runAgent 是 `backupx agent` 子命令入口。
Expand Down Expand Up @@ -59,11 +61,23 @@ func runAgent(args []string) {
os.Exit(2)
}

agentLogger, err := applogger.New(config.LogConfig{Level: "info"})
if err != nil {
fmt.Fprintf(os.Stderr, "agent: init logger: %v\n", err)
os.Exit(1)
}
defer func() {
if syncErr := agentLogger.Sync(); syncErr != nil {
fmt.Fprintf(os.Stderr, "agent: flush logger: %v\n", syncErr)
}
}()

a, err := agent.New(cfg, version)
if err != nil {
fmt.Fprintf(os.Stderr, "agent: init: %v\n", err)
os.Exit(1)
}
a.SetLogger(agentLogger)

ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer stop()
Expand Down
Loading