将项目级的 Ratchet/约定检测方法论融入 req-test-gate 技能, 通过 /req 流程三个节点自动触发(dev 环境检测、cr 约定建议、test Gate 0B), 无需手动记忆执行。 新增文档:harness-engineering.md、ratchet-pattern.md、convention-flow.md、 project-bootstrap.md 及 4 个模板(ratchet/convention 脚本、GATES.md、pre-commit)。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
817 lines
18 KiB
Markdown
817 lines
18 KiB
Markdown
---
|
||
name: dev-coding
|
||
description: 软件编码开发技能。用于代码编写、功能实现、代码审查、重构优化。集成 ai-proj CLI 进行任务管理和进度跟踪。支持 Go、Vue、React、iOS、Android、小程序等全栈开发。
|
||
---
|
||
|
||
# 软件编码开发 Skill (dev-coding)
|
||
|
||
## ⚠️ REQ 任务自动工作流
|
||
|
||
**当收到 REQ 任务(包含 REQ-YYYYMMDD-XXXX)需要开发时,必须严格按以下顺序执行:**
|
||
|
||
1. **读取 ticket** — 从 ai-proj 获取需求详情和关联文档
|
||
```
|
||
mcp__ai-proj-dev__get_detailed_task_info (通过 REQ 号查找)
|
||
mcp__ai-proj-dev__get_task_document (如果有 PRD 文档)
|
||
```
|
||
|
||
2. **进入 Plan Mode** — 调用 `EnterPlanMode` 工具
|
||
- 分析需求,探索代码库,设计实现方案
|
||
- 输出实现计划(涉及的文件、改动范围、测试策略)
|
||
- 等待用户审批后再开始编码
|
||
|
||
3. **执行计划** — 用户批准后按计划编码 + 写测试
|
||
|
||
**禁止跳过 plan mode 直接编码。**
|
||
|
||
---
|
||
|
||
## 概述
|
||
|
||
本技能用于软件编码开发工作,支持多种项目类型:
|
||
- Go 后端 (Gin + GORM)
|
||
- Vue 3 / React 前端
|
||
- iOS (Swift/SwiftUI)
|
||
- Android (Kotlin/Jetpack Compose)
|
||
- PDA 应用
|
||
- MCP 桥接服务
|
||
- 微服务架构
|
||
|
||
核心集成 **ai-proj CLI** 进行任务管理。
|
||
|
||
---
|
||
|
||
## ai-proj 任务管理
|
||
|
||
### 开发任务工作流
|
||
|
||
```
|
||
1. 查看/创建任务 → 2. 启动任务 → 3. 编码实现 → 4. 完成任务 → 5. 记录文档
|
||
```
|
||
|
||
### 任务操作速查
|
||
|
||
| 操作 | CLI 命令 | 说明 |
|
||
|------|----------|------|
|
||
| 查看任务列表 | `ai-proj task list` | 查看项目所有任务 |
|
||
| 创建任务 | `ai-proj task create` | 创建新任务 |
|
||
| 创建子任务 | `ai-proj task create --parent-id` | 分解任务 |
|
||
| 启动任务 | `ai-proj task start --id` | 开始执行 |
|
||
| 完成任务 | `ai-proj task complete --id` | 标记完成 |
|
||
| 更新任务 | `ai-proj task update --id` | 更新状态/描述 |
|
||
| 查看详情 | `ai-proj task get --id` | 完整任务信息 |
|
||
| 记录文档 | `ai-proj task append-doc --id` | 附加文档 |
|
||
|
||
### 开始新任务
|
||
|
||
```bash
|
||
# 1. 查看任务列表
|
||
ai-proj task list --status todo,in_progress
|
||
|
||
# 2. 启动任务
|
||
ai-proj task start --id <taskId>
|
||
|
||
# 3. 完成后
|
||
ai-proj task complete --id <taskId>
|
||
|
||
# 4. 记录文档
|
||
ai-proj task append-doc --id <taskId> --content "实现说明"
|
||
```
|
||
|
||
---
|
||
|
||
## 项目类型速查
|
||
|
||
### 当前项目生态
|
||
|
||
| 项目 | 类型 | 后端 | 前端 | 移动端 |
|
||
|------|------|------|------|--------|
|
||
| TWMS | 仓储物流 | Go+Gin+MySQL | Vue 3 | - |
|
||
| AI-Proj | 项目管理 | Go+Gin+PostgreSQL | React 18 | iOS+Android |
|
||
| DICIAI | 进销存SaaS | Go+Gin+MySQL | Vue 3 | Android PDA |
|
||
|
||
---
|
||
|
||
## Go 后端开发
|
||
|
||
### 分层架构
|
||
|
||
```
|
||
backend/
|
||
├── cmd/main.go # 入口点
|
||
├── internal/
|
||
│ ├── controller/handlers/ # HTTP 处理层
|
||
│ ├── biz/services/ # 业务逻辑层
|
||
│ ├── store/database/ # 数据访问层
|
||
│ └── middleware/ # 中间件
|
||
├── pkg/
|
||
│ ├── model/ # 数据模型
|
||
│ ├── errno/ # 错误定义
|
||
│ ├── api/ # API 类型
|
||
│ └── util/ # 工具函数
|
||
└── configs/migrations/ # 配置和迁移
|
||
```
|
||
|
||
### 代码规范
|
||
|
||
```go
|
||
// 包声明和导入组织
|
||
package main
|
||
|
||
import (
|
||
// 标准库
|
||
"context"
|
||
"fmt"
|
||
|
||
// 第三方
|
||
"github.com/gin-gonic/gin"
|
||
|
||
// 项目内部
|
||
"project/internal/pkg/errno"
|
||
)
|
||
|
||
// 错误处理 (Errno 模式)
|
||
if err != nil {
|
||
core.WriteResponse(c, errno.ErrBind, nil)
|
||
return
|
||
}
|
||
|
||
// 接口定义
|
||
type IStore interface {
|
||
Users() UserStore
|
||
}
|
||
|
||
// 服务注入
|
||
type userBiz struct {
|
||
ds store.IStore
|
||
}
|
||
|
||
func NewUserBiz(ds store.IStore) *userBiz {
|
||
return &userBiz{ds: ds}
|
||
}
|
||
```
|
||
|
||
### 常用命令
|
||
|
||
```bash
|
||
# 构建
|
||
make build
|
||
go build -o ./_output/main ./cmd/main.go
|
||
|
||
# 运行
|
||
./_output/main --config ./configs/config.yaml
|
||
|
||
# 测试
|
||
make test
|
||
go test -v ./...
|
||
|
||
# 代码检查
|
||
make lint
|
||
golangci-lint run
|
||
|
||
# Swagger 文档
|
||
make swagger
|
||
swag init -g cmd/main.go
|
||
```
|
||
|
||
### 数据库模型
|
||
|
||
```go
|
||
type UserM struct {
|
||
Id int64 `gorm:"column:id;primary_key"`
|
||
Username string `gorm:"column:username;not null"`
|
||
CreateTime int64 `gorm:"column:create_time"`
|
||
UpdateTime int64 `gorm:"column:update_time"`
|
||
DeletedAt soft_delete.DeletedAt `gorm:"column:deleted_at"`
|
||
}
|
||
|
||
func (m *UserM) TableName() string { return "users" }
|
||
|
||
func (m *UserM) BeforeCreate(tx *gorm.DB) error {
|
||
m.CreateTime = time.Now().Unix()
|
||
m.UpdateTime = m.CreateTime
|
||
return nil
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 前端 data-testid 规范
|
||
|
||
编写或修改前端组件时,**所有可交互元素必须加 `data-testid`**。
|
||
|
||
**命名格式:** `<模块>-<元素类型>[-<标识>]`
|
||
|
||
```vue
|
||
<!-- ✅ 正确 -->
|
||
<a-input data-testid="product-input-name" v-model:value="form.name" placeholder="商品名称" />
|
||
<a-button data-testid="product-btn-submit" type="primary">创建商品</a-button>
|
||
<a-select data-testid="product-select-brand" v-model:value="form.brandId" />
|
||
<a-table data-testid="product-table" :dataSource="list" />
|
||
|
||
<!-- ❌ 错误 — 交互元素无 data-testid -->
|
||
<a-input v-model:value="form.name" placeholder="商品名称" />
|
||
<a-button type="primary">创建商品</a-button>
|
||
```
|
||
|
||
**必须加:** 输入框、选择器、开关、按钮(提交/取消/删除)、表格、模态框确认按钮、导航菜单项
|
||
**不需要加:** 纯展示文本、图标、布局容器(Row/Col/Space)
|
||
|
||
---
|
||
|
||
## Vue 3 前端开发
|
||
|
||
### 项目结构
|
||
|
||
```
|
||
frontend/src/
|
||
├── api/ # API 服务 (按模块分组)
|
||
│ ├── wms/ # 仓储管理
|
||
│ ├── oms/ # 订单管理
|
||
│ └── system/ # 系统管理
|
||
├── views/ # 页面组件
|
||
├── components/ # 可复用组件
|
||
├── store/modules/ # Pinia 状态
|
||
├── router/ # 路由配置
|
||
├── utils/
|
||
│ ├── request.ts # Axios 拦截器
|
||
│ └── permission.ts # 权限检查
|
||
└── i18n/ # 国际化
|
||
```
|
||
|
||
### 代码规范
|
||
|
||
```typescript
|
||
// API 服务层
|
||
// api/user/model/index.ts
|
||
export interface User {
|
||
id: number;
|
||
username: string;
|
||
}
|
||
|
||
// api/user/index.ts
|
||
import request from '@/utils/request';
|
||
import type { ApiResult, PageResult } from '@/api';
|
||
import type { User } from './model';
|
||
|
||
export async function getUsers(params: UserParams) {
|
||
const res = await request.get<ApiResult<PageResult<User>>>(
|
||
'/v1/users',
|
||
{ params }
|
||
);
|
||
if (res.status === 200) {
|
||
return res.data;
|
||
}
|
||
return Promise.reject(new Error(res.data.message));
|
||
}
|
||
```
|
||
|
||
### 常用命令
|
||
|
||
```bash
|
||
# 安装依赖
|
||
npm install
|
||
pnpm install # DICIAI 使用 pnpm
|
||
|
||
# 开发
|
||
npm run dev
|
||
|
||
# 构建
|
||
npm run build:prod
|
||
npm run build:test
|
||
|
||
# 代码检查
|
||
npm run lint:eslint
|
||
```
|
||
|
||
---
|
||
|
||
## React 前端开发
|
||
|
||
### 项目结构
|
||
|
||
```
|
||
frontend/src/
|
||
├── pages/ # 页面组件
|
||
├── components/ # 可复用组件
|
||
├── services/ # API 服务
|
||
├── hooks/ # 自定义 Hooks
|
||
├── contexts/ # Context Providers
|
||
├── types/ # TypeScript 类型
|
||
├── utils/ # 工具函数
|
||
└── config/ # 配置
|
||
```
|
||
|
||
### 代码规范
|
||
|
||
```typescript
|
||
// Context 集成
|
||
<QueryProvider>
|
||
<AuthProvider>
|
||
<TimerProvider>
|
||
<ConfigProvider locale={zhCN}>
|
||
<Router>
|
||
<Routes />
|
||
</Router>
|
||
</ConfigProvider>
|
||
</TimerProvider>
|
||
</AuthProvider>
|
||
</QueryProvider>
|
||
|
||
// API 服务
|
||
const api = axios.create({
|
||
baseURL: API_BASE_URL,
|
||
timeout: 120000,
|
||
});
|
||
|
||
api.interceptors.request.use((config) => {
|
||
const token = TokenManager.getToken();
|
||
if (token) {
|
||
config.headers.Authorization = `Bearer ${token}`;
|
||
}
|
||
return config;
|
||
});
|
||
```
|
||
|
||
### 常用命令
|
||
|
||
```bash
|
||
# 开发
|
||
npm start
|
||
|
||
# 构建
|
||
npm run build
|
||
|
||
# 测试
|
||
npm test
|
||
npm run test:e2e
|
||
```
|
||
|
||
---
|
||
|
||
## iOS 开发 (Swift/SwiftUI)
|
||
|
||
### 项目结构
|
||
|
||
```
|
||
AI-Proj-iOS/
|
||
├── Core/ # 核心服务
|
||
│ ├── Network/ # 网络层
|
||
│ ├── Storage/ # 本地存储
|
||
│ └── Auth/ # 认证
|
||
├── Features/ # 功能模块
|
||
│ ├── Dashboard/
|
||
│ ├── Tasks/
|
||
│ └── Settings/
|
||
├── Models/ # 数据模型
|
||
└── UI/ # UI 组件
|
||
```
|
||
|
||
### 代码规范
|
||
|
||
```swift
|
||
// MVVM 架构
|
||
class TaskViewModel: ObservableObject {
|
||
@Published var tasks: [Task] = []
|
||
@Published var isLoading = false
|
||
|
||
private let taskService: TaskServiceProtocol
|
||
|
||
init(taskService: TaskServiceProtocol = TaskService()) {
|
||
self.taskService = taskService
|
||
}
|
||
|
||
func fetchTasks() async {
|
||
isLoading = true
|
||
defer { isLoading = false }
|
||
|
||
do {
|
||
tasks = try await taskService.getTasks()
|
||
} catch {
|
||
// 错误处理
|
||
}
|
||
}
|
||
}
|
||
|
||
// SwiftUI 视图
|
||
struct TaskListView: View {
|
||
@StateObject private var viewModel = TaskViewModel()
|
||
|
||
var body: some View {
|
||
List(viewModel.tasks) { task in
|
||
TaskRow(task: task)
|
||
}
|
||
.task {
|
||
await viewModel.fetchTasks()
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 构建命令
|
||
|
||
```bash
|
||
# Xcode 构建
|
||
xcodebuild -scheme AI-Proj-iOS -configuration Debug
|
||
|
||
# 测试
|
||
xcodebuild test -scheme AI-Proj-iOS
|
||
```
|
||
|
||
### 常见问题排查
|
||
|
||
#### SwiftLint 沙盒错误
|
||
|
||
**问题描述**:
|
||
构建时出现错误:
|
||
```
|
||
Sandbox: swiftlint(xxxx) deny(1) file-read-data /path/to/.swiftlint.yml
|
||
```
|
||
|
||
**原因**:
|
||
Xcode 15+ 默认启用 User Script Sandboxing,限制脚本访问文件系统。
|
||
|
||
**解决方案**:
|
||
|
||
方案 1 - 修改项目配置(推荐):
|
||
1. 打开 Xcode → 选择项目 → Build Settings
|
||
2. 搜索 "User Script Sandboxing"
|
||
3. 将 `ENABLE_USER_SCRIPT_SANDBOXING` 设置为 `NO`
|
||
|
||
方案 2 - 命令行构建时禁用:
|
||
```bash
|
||
xcodebuild -scheme AI-Proj-iOS -configuration Debug \
|
||
ENABLE_USER_SCRIPT_SANDBOXING=NO
|
||
```
|
||
|
||
方案 3 - 直接修改 project.pbxproj:
|
||
```bash
|
||
sed -i '' 's/ENABLE_USER_SCRIPT_SANDBOXING = YES/ENABLE_USER_SCRIPT_SANDBOXING = NO/g' \
|
||
AI-Proj-iOS.xcodeproj/project.pbxproj
|
||
```
|
||
|
||
#### Personal Development Team 功能限制
|
||
|
||
**问题描述**:
|
||
使用免费 Personal Team 签名时报错:
|
||
```
|
||
Cannot create iOS App Development provisioning profile...
|
||
Personal development teams do not support the Associated Domains,
|
||
Push Notifications and App Groups capabilities.
|
||
```
|
||
|
||
**原因**:
|
||
Personal Team(免费账户)不支持以下 Entitlements:
|
||
- Associated Domains (`com.apple.developer.associated-domains`)
|
||
- Push Notifications (`aps-environment`)
|
||
- App Groups (`com.apple.security.application-groups`)
|
||
|
||
**解决方案**:
|
||
|
||
1. 从 Entitlements 文件中移除不支持的功能:
|
||
|
||
```xml
|
||
<!-- AI-Proj-iOS.entitlements -->
|
||
<?xml version="1.0" encoding="UTF-8"?>
|
||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||
<plist version="1.0">
|
||
<dict>
|
||
<!-- 仅保留 Personal Team 支持的功能 -->
|
||
<key>keychain-access-groups</key>
|
||
<array>
|
||
<string>$(AppIdentifierPrefix)com.yourcompany.app</string>
|
||
</array>
|
||
</dict>
|
||
</plist>
|
||
```
|
||
|
||
2. Personal Team 支持的功能:
|
||
- Keychain Access Groups ✓
|
||
- In-App Purchase ✓
|
||
- Game Center ✓
|
||
|
||
3. 需要付费 Apple Developer Program 的功能:
|
||
- Push Notifications ✗
|
||
- Associated Domains ✗
|
||
- App Groups ✗
|
||
- CloudKit ✗
|
||
- Sign in with Apple ✗
|
||
|
||
---
|
||
|
||
## Android 开发 (Kotlin)
|
||
|
||
### 项目结构
|
||
|
||
```
|
||
android-app/app/src/main/
|
||
├── java/com/project/
|
||
│ ├── ui/ # UI 层
|
||
│ │ ├── screens/ # Compose 屏幕
|
||
│ │ └── components/ # 可复用组件
|
||
│ ├── data/ # 数据层
|
||
│ │ ├── api/ # 网络接口
|
||
│ │ ├── repository/ # 仓库模式
|
||
│ │ └── local/ # 本地存储
|
||
│ ├── domain/ # 业务逻辑
|
||
│ └── di/ # 依赖注入
|
||
└── res/ # 资源文件
|
||
```
|
||
|
||
### 代码规范
|
||
|
||
```kotlin
|
||
// Hilt 依赖注入
|
||
@HiltViewModel
|
||
class TaskViewModel @Inject constructor(
|
||
private val taskRepository: TaskRepository
|
||
) : ViewModel() {
|
||
|
||
private val _tasks = MutableStateFlow<List<Task>>(emptyList())
|
||
val tasks: StateFlow<List<Task>> = _tasks.asStateFlow()
|
||
|
||
fun fetchTasks() {
|
||
viewModelScope.launch {
|
||
taskRepository.getTasks()
|
||
.collect { _tasks.value = it }
|
||
}
|
||
}
|
||
}
|
||
|
||
// Jetpack Compose
|
||
@Composable
|
||
fun TaskListScreen(
|
||
viewModel: TaskViewModel = hiltViewModel()
|
||
) {
|
||
val tasks by viewModel.tasks.collectAsState()
|
||
|
||
LazyColumn {
|
||
items(tasks) { task ->
|
||
TaskItem(task = task)
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 构建命令
|
||
|
||
```bash
|
||
# 构建 Debug
|
||
./gradlew assembleDebug
|
||
|
||
# 构建 Release
|
||
./gradlew assembleRelease
|
||
|
||
# 测试
|
||
./gradlew test
|
||
```
|
||
|
||
---
|
||
|
||
## PDA 应用开发
|
||
|
||
### 特点
|
||
|
||
- Android 原生开发
|
||
- 扫码枪集成
|
||
- 离线优先
|
||
- 简洁 UI
|
||
|
||
### 常见功能
|
||
|
||
```kotlin
|
||
// 扫码处理
|
||
class ScanReceiver : BroadcastReceiver() {
|
||
override fun onReceive(context: Context, intent: Intent) {
|
||
val barcode = intent.getStringExtra("SCAN_BARCODE")
|
||
// 处理扫码结果
|
||
}
|
||
}
|
||
|
||
// 离线存储
|
||
@Entity(tableName = "inventory")
|
||
data class Inventory(
|
||
@PrimaryKey val id: Long,
|
||
val barcode: String,
|
||
val quantity: Int,
|
||
@ColumnInfo(name = "sync_status")
|
||
val syncStatus: SyncStatus = SyncStatus.PENDING
|
||
)
|
||
```
|
||
|
||
---
|
||
|
||
## MCP 桥接开发
|
||
|
||
### 项目结构
|
||
|
||
```
|
||
mcp-task-bridge/
|
||
├── index.ts # 入口
|
||
├── task-service.ts # 任务服务
|
||
├── document-service.ts # 文档服务
|
||
├── base-client.ts # HTTP 基类
|
||
├── types.ts # 类型定义
|
||
└── token-storage.ts # Token 管理
|
||
```
|
||
|
||
### 代码规范
|
||
|
||
```typescript
|
||
// 服务类模式
|
||
export class TaskService extends BaseClient {
|
||
async createTask(
|
||
title: string,
|
||
projectId: number = 1,
|
||
options: CreateTaskOptions = {}
|
||
): Promise<ApiResponse<Task>> {
|
||
try {
|
||
const response = await this.makeRequest<Task>(
|
||
'POST',
|
||
`/projects/${projectId}/tasks`,
|
||
{ title, project_id: projectId, ...options }
|
||
);
|
||
|
||
if (response.success) {
|
||
return {
|
||
success: true,
|
||
data: response.data,
|
||
message: `✅ 任务 "${title}" 创建成功`
|
||
};
|
||
}
|
||
return response;
|
||
} catch (error: any) {
|
||
return {
|
||
success: false,
|
||
error: `创建任务失败: ${error.message}`
|
||
};
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 通用开发规范
|
||
|
||
### API 响应格式
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "success",
|
||
"data": {}
|
||
}
|
||
```
|
||
|
||
### 分页参数
|
||
|
||
```json
|
||
{
|
||
"page": 1,
|
||
"limit": 20,
|
||
"sort": "created_at",
|
||
"order": "desc"
|
||
}
|
||
```
|
||
|
||
### 认证方式
|
||
|
||
- JWT Token
|
||
- Header: `Authorization: Bearer <token>`
|
||
|
||
### 错误处理
|
||
|
||
```go
|
||
// Go
|
||
if err != nil {
|
||
core.WriteResponse(c, errno.ErrXxx, nil)
|
||
return
|
||
}
|
||
|
||
// TypeScript
|
||
try {
|
||
const result = await api.call();
|
||
} catch (error) {
|
||
message.error(error.message);
|
||
}
|
||
|
||
// Swift
|
||
do {
|
||
let result = try await service.fetch()
|
||
} catch {
|
||
// 处理错误
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Git 工作流
|
||
|
||
### 提交规范
|
||
|
||
| 类型 | 说明 |
|
||
|------|------|
|
||
| feat | 新功能 |
|
||
| fix | Bug 修复 |
|
||
| docs | 文档 |
|
||
| refactor | 重构 |
|
||
| test | 测试 |
|
||
| chore | 杂项 |
|
||
|
||
### 双电脑同步 (au-dev / cn-dev)
|
||
|
||
```bash
|
||
# 离开时
|
||
git add -A
|
||
git commit -m "WIP: sync from $(hostname)"
|
||
git push origin $(git branch --show-current)
|
||
|
||
# 到达时
|
||
git fetch origin
|
||
git pull origin $(git branch --show-current)
|
||
```
|
||
|
||
---
|
||
|
||
## Docker 部署
|
||
|
||
### 标准配置
|
||
|
||
```yaml
|
||
# docker-compose.yml
|
||
services:
|
||
backend:
|
||
build: ./backend
|
||
ports:
|
||
- "8080:8080"
|
||
depends_on:
|
||
- db
|
||
- redis
|
||
|
||
frontend:
|
||
build: ./frontend
|
||
ports:
|
||
- "80:80"
|
||
|
||
db:
|
||
image: mysql:8.0
|
||
# 或 postgres:15
|
||
|
||
redis:
|
||
image: redis:alpine
|
||
```
|
||
|
||
### 常用端口
|
||
|
||
| 服务 | 端口 |
|
||
|------|------|
|
||
| Backend | 8080 / 9099 |
|
||
| Frontend | 80 / 3000 |
|
||
| MySQL | 3306 |
|
||
| PostgreSQL | 5432 |
|
||
| Redis | 6379 |
|
||
|
||
---
|
||
|
||
## Push 前必须通过:变更包单元测试
|
||
|
||
**在 `git push` 或 `/pr create` 之前,必须跑所有变更文件对应包的单元测试。**
|
||
|
||
```bash
|
||
# 找出变更的 Go 文件所在包,跑对应测试
|
||
PKGS=$(git diff --name-only origin/main...HEAD | grep '\.go$' | grep -v '_test\.go' | sed 's|/[^/]*$||' | sort -u | sed 's|^|./|' | tr '\n' ' ')
|
||
|
||
if [ -n "$PKGS" ]; then
|
||
echo "Running tests for changed packages: $PKGS"
|
||
go test -v -count=1 $PKGS
|
||
else
|
||
echo "No Go files changed, skipping tests"
|
||
fi
|
||
```
|
||
|
||
**规则:**
|
||
- 测试通过 → 继续 push + `/pr create`
|
||
- 测试失败 → 尝试自动修复,修复后重跑
|
||
- 修复成功 → 继续 push
|
||
- **修复失败 → 禁止 push,向用户报告失败原因,等待指示**
|
||
- 仅改了 `_test.go` → 同样需要跑(验证测试本身通过)
|
||
- 无 Go 文件变更(纯前端/文档) → 跳过
|
||
|
||
---
|
||
|
||
## 最佳实践
|
||
|
||
1. **任务驱动** - 使用 ai-proj 管理所有开发任务
|
||
2. **分层清晰** - Controller → Service → Repository
|
||
3. **接口先行** - 先定义接口再实现
|
||
4. **小步提交** - 频繁提交,每次做一件事
|
||
5. **测试覆盖** - 核心逻辑必须有测试
|
||
6. **文档同步** - 代码变更同步更新文档
|
||
|
||
## 相关技能
|
||
|
||
| 技能 | 用途 | 关系 |
|
||
|------|------|------|
|
||
| `req-test-gate` | 测试与质量门禁 + Harness Engineering | 建立项目质量门禁和约定自动检测,dev-coding 遵守其建立的 CLAUDE.md 约定 |
|