ccgx-workflow 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -5
- package/README.zh-CN.md +35 -5
- package/dist/cli.mjs +1 -1
- package/dist/index.mjs +2 -2
- package/dist/shared/{ccgx-workflow.WgUzkiC3.mjs → ccgx-workflow.Bq9vAaEw.mjs} +17 -110
- package/package.json +2 -1
- package/templates/commands/agents/phase-runner.md +321 -321
- package/templates/commands/autonomous.md +792 -792
- package/templates/commands/cancel.md +132 -132
- package/templates/commands/debug.md +226 -226
- package/templates/commands/status.md +206 -206
- package/templates/commands/team.md +484 -0
- package/templates/hooks/ccg-session-state.cjs +566 -510
- package/templates/scripts/ccg-phase-runner-launcher.mjs +467 -467
- package/templates/scripts/invoke-model.mjs +64 -0
- package/templates/skills/domains/ai/SKILL.md +35 -35
- package/templates/skills/domains/ai/agent-dev.md +242 -242
- package/templates/skills/domains/ai/llm-security.md +288 -288
- package/templates/skills/domains/ai/rag-system.md +542 -542
- package/templates/skills/domains/architecture/SKILL.md +43 -43
- package/templates/skills/domains/architecture/api-design.md +225 -225
- package/templates/skills/domains/architecture/cloud-native.md +285 -285
- package/templates/skills/domains/architecture/security-arch.md +297 -297
- package/templates/skills/domains/data-engineering/SKILL.md +208 -208
- package/templates/skills/domains/development/SKILL.md +47 -47
- package/templates/skills/domains/development/cpp.md +246 -246
- package/templates/skills/domains/development/go.md +323 -323
- package/templates/skills/domains/development/java.md +277 -277
- package/templates/skills/domains/development/python.md +288 -288
- package/templates/skills/domains/development/rust.md +313 -313
- package/templates/skills/domains/development/shell.md +313 -313
- package/templates/skills/domains/development/typescript.md +277 -277
- package/templates/skills/domains/devops/SKILL.md +40 -40
- package/templates/skills/domains/devops/database.md +217 -217
- package/templates/skills/domains/devops/devsecops.md +198 -198
- package/templates/skills/domains/devops/git-workflow.md +181 -181
- package/templates/skills/domains/devops/testing.md +283 -283
- package/templates/skills/domains/frontend-design/SKILL.md +244 -244
- package/templates/skills/domains/frontend-design/claymorphism/SKILL.md +121 -121
- package/templates/skills/domains/frontend-design/component-patterns.md +202 -202
- package/templates/skills/domains/frontend-design/glassmorphism/SKILL.md +142 -142
- package/templates/skills/domains/frontend-design/liquid-glass/SKILL.md +139 -139
- package/templates/skills/domains/frontend-design/neubrutalism/SKILL.md +145 -145
- package/templates/skills/domains/frontend-design/state-management.md +680 -680
- package/templates/skills/domains/frontend-design/ui-aesthetics.md +110 -110
- package/templates/skills/domains/frontend-design/ux-principles.md +156 -156
- package/templates/skills/domains/infrastructure/SKILL.md +201 -201
- package/templates/skills/domains/mobile/SKILL.md +225 -225
- package/templates/skills/domains/orchestration/SKILL.md +30 -30
- package/templates/skills/domains/orchestration/multi-agent.md +228 -228
- package/templates/skills/domains/security/SKILL.md +73 -73
- package/templates/skills/domains/security/blue-team.md +436 -436
- package/templates/skills/domains/security/code-audit.md +265 -265
- package/templates/skills/domains/security/pentest.md +226 -226
- package/templates/skills/domains/security/red-team.md +374 -374
- package/templates/skills/domains/security/threat-intel.md +372 -372
- package/templates/skills/domains/security/vuln-research.md +369 -369
- package/templates/skills/tools/lib/shared.js +98 -98
- package/templates/skills/tools/override-refusal/SKILL.md +53 -53
- package/templates/skills/tools/override-refusal/scripts/refusal_rewriter.js +226 -226
|
@@ -1,323 +1,323 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: go
|
|
3
|
-
description: Go 开发。高并发、微服务、云原生、CLI工具。当用户提到 Go、Golang、Gin、Echo、goroutine 时使用。
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# 📜 符箓秘典 · Go
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
## Web 框架
|
|
10
|
-
|
|
11
|
-
### Gin
|
|
12
|
-
```go
|
|
13
|
-
package main
|
|
14
|
-
|
|
15
|
-
import (
|
|
16
|
-
"net/http"
|
|
17
|
-
"github.com/gin-gonic/gin"
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
type User struct {
|
|
21
|
-
ID int `json:"id"`
|
|
22
|
-
Name string `json:"name" binding:"required"`
|
|
23
|
-
Email string `json:"email" binding:"required,email"`
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
func main() {
|
|
27
|
-
r := gin.Default()
|
|
28
|
-
|
|
29
|
-
// 中间件
|
|
30
|
-
r.Use(gin.Logger())
|
|
31
|
-
r.Use(gin.Recovery())
|
|
32
|
-
|
|
33
|
-
// 路由组
|
|
34
|
-
api := r.Group("/api")
|
|
35
|
-
{
|
|
36
|
-
api.GET("/users/:id", getUser)
|
|
37
|
-
api.POST("/users", createUser)
|
|
38
|
-
api.PUT("/users/:id", updateUser)
|
|
39
|
-
api.DELETE("/users/:id", deleteUser)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
r.Run(":8080")
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
func getUser(c *gin.Context) {
|
|
46
|
-
id := c.Param("id")
|
|
47
|
-
c.JSON(http.StatusOK, gin.H{"id": id})
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
func createUser(c *gin.Context) {
|
|
51
|
-
var user User
|
|
52
|
-
if err := c.ShouldBindJSON(&user); err != nil {
|
|
53
|
-
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
54
|
-
return
|
|
55
|
-
}
|
|
56
|
-
c.JSON(http.StatusCreated, user)
|
|
57
|
-
}
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
### Echo
|
|
61
|
-
```go
|
|
62
|
-
package main
|
|
63
|
-
|
|
64
|
-
import (
|
|
65
|
-
"net/http"
|
|
66
|
-
"github.com/labstack/echo/v4"
|
|
67
|
-
"github.com/labstack/echo/v4/middleware"
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
func main() {
|
|
71
|
-
e := echo.New()
|
|
72
|
-
|
|
73
|
-
e.Use(middleware.Logger())
|
|
74
|
-
e.Use(middleware.Recover())
|
|
75
|
-
|
|
76
|
-
e.GET("/users/:id", getUser)
|
|
77
|
-
e.POST("/users", createUser)
|
|
78
|
-
|
|
79
|
-
e.Logger.Fatal(e.Start(":8080"))
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
func getUser(c echo.Context) error {
|
|
83
|
-
id := c.Param("id")
|
|
84
|
-
return c.JSON(http.StatusOK, map[string]string{"id": id})
|
|
85
|
-
}
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
## 并发编程
|
|
89
|
-
|
|
90
|
-
### Goroutine & Channel
|
|
91
|
-
```go
|
|
92
|
-
package main
|
|
93
|
-
|
|
94
|
-
import (
|
|
95
|
-
"fmt"
|
|
96
|
-
"sync"
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
// 基础并发
|
|
100
|
-
func worker(id int, jobs <-chan int, results chan<- int) {
|
|
101
|
-
for j := range jobs {
|
|
102
|
-
results <- j * 2
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
func main() {
|
|
107
|
-
jobs := make(chan int, 100)
|
|
108
|
-
results := make(chan int, 100)
|
|
109
|
-
|
|
110
|
-
// 启动 worker
|
|
111
|
-
for w := 1; w <= 3; w++ {
|
|
112
|
-
go worker(w, jobs, results)
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// 发送任务
|
|
116
|
-
for j := 1; j <= 9; j++ {
|
|
117
|
-
jobs <- j
|
|
118
|
-
}
|
|
119
|
-
close(jobs)
|
|
120
|
-
|
|
121
|
-
// 收集结果
|
|
122
|
-
for a := 1; a <= 9; a++ {
|
|
123
|
-
<-results
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// WaitGroup
|
|
128
|
-
func parallelFetch(urls []string) []string {
|
|
129
|
-
var wg sync.WaitGroup
|
|
130
|
-
results := make([]string, len(urls))
|
|
131
|
-
|
|
132
|
-
for i, url := range urls {
|
|
133
|
-
wg.Add(1)
|
|
134
|
-
go func(i int, url string) {
|
|
135
|
-
defer wg.Done()
|
|
136
|
-
results[i] = fetch(url)
|
|
137
|
-
}(i, url)
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
wg.Wait()
|
|
141
|
-
return results
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Context 控制
|
|
145
|
-
func fetchWithTimeout(ctx context.Context, url string) (string, error) {
|
|
146
|
-
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
|
147
|
-
defer cancel()
|
|
148
|
-
|
|
149
|
-
req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
|
|
150
|
-
resp, err := http.DefaultClient.Do(req)
|
|
151
|
-
if err != nil {
|
|
152
|
-
return "", err
|
|
153
|
-
}
|
|
154
|
-
defer resp.Body.Close()
|
|
155
|
-
|
|
156
|
-
body, _ := io.ReadAll(resp.Body)
|
|
157
|
-
return string(body), nil
|
|
158
|
-
}
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
## 错误处理
|
|
162
|
-
|
|
163
|
-
```go
|
|
164
|
-
package main
|
|
165
|
-
|
|
166
|
-
import (
|
|
167
|
-
"errors"
|
|
168
|
-
"fmt"
|
|
169
|
-
)
|
|
170
|
-
|
|
171
|
-
// 自定义错误
|
|
172
|
-
var ErrNotFound = errors.New("not found")
|
|
173
|
-
|
|
174
|
-
type ValidationError struct {
|
|
175
|
-
Field string
|
|
176
|
-
Message string
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
func (e *ValidationError) Error() string {
|
|
180
|
-
return fmt.Sprintf("%s: %s", e.Field, e.Message)
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// 错误包装
|
|
184
|
-
func getUser(id int) (*User, error) {
|
|
185
|
-
user, err := db.FindUser(id)
|
|
186
|
-
if err != nil {
|
|
187
|
-
return nil, fmt.Errorf("getUser(%d): %w", id, err)
|
|
188
|
-
}
|
|
189
|
-
return user, nil
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
// 错误检查
|
|
193
|
-
func handleUser(id int) error {
|
|
194
|
-
user, err := getUser(id)
|
|
195
|
-
if err != nil {
|
|
196
|
-
if errors.Is(err, ErrNotFound) {
|
|
197
|
-
return nil // 忽略未找到
|
|
198
|
-
}
|
|
199
|
-
return err
|
|
200
|
-
}
|
|
201
|
-
// 处理 user
|
|
202
|
-
return nil
|
|
203
|
-
}
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
## 测试
|
|
207
|
-
|
|
208
|
-
```go
|
|
209
|
-
package main
|
|
210
|
-
|
|
211
|
-
import (
|
|
212
|
-
"testing"
|
|
213
|
-
"github.com/stretchr/testify/assert"
|
|
214
|
-
)
|
|
215
|
-
|
|
216
|
-
func TestAdd(t *testing.T) {
|
|
217
|
-
result := Add(1, 2)
|
|
218
|
-
assert.Equal(t, 3, result)
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// 表驱动测试
|
|
222
|
-
func TestAddTable(t *testing.T) {
|
|
223
|
-
tests := []struct {
|
|
224
|
-
name string
|
|
225
|
-
a, b int
|
|
226
|
-
expected int
|
|
227
|
-
}{
|
|
228
|
-
{"positive", 1, 2, 3},
|
|
229
|
-
{"zero", 0, 0, 0},
|
|
230
|
-
{"negative", -1, 1, 0},
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
for _, tt := range tests {
|
|
234
|
-
t.Run(tt.name, func(t *testing.T) {
|
|
235
|
-
assert.Equal(t, tt.expected, Add(tt.a, tt.b))
|
|
236
|
-
})
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// Benchmark
|
|
241
|
-
func BenchmarkAdd(b *testing.B) {
|
|
242
|
-
for i := 0; i < b.N; i++ {
|
|
243
|
-
Add(1, 2)
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
```bash
|
|
249
|
-
go test ./...
|
|
250
|
-
go test -v
|
|
251
|
-
go test -cover
|
|
252
|
-
go test -bench=.
|
|
253
|
-
go test -race # 竞态检测
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
## CLI 工具
|
|
257
|
-
|
|
258
|
-
### Cobra
|
|
259
|
-
```go
|
|
260
|
-
package main
|
|
261
|
-
|
|
262
|
-
import (
|
|
263
|
-
"fmt"
|
|
264
|
-
"github.com/spf13/cobra"
|
|
265
|
-
)
|
|
266
|
-
|
|
267
|
-
var rootCmd = &cobra.Command{
|
|
268
|
-
Use: "myapp",
|
|
269
|
-
Short: "My CLI application",
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
var serveCmd = &cobra.Command{
|
|
273
|
-
Use: "serve",
|
|
274
|
-
Short: "Start the server",
|
|
275
|
-
Run: func(cmd *cobra.Command, args []string) {
|
|
276
|
-
port, _ := cmd.Flags().GetInt("port")
|
|
277
|
-
fmt.Printf("Starting server on port %d\n", port)
|
|
278
|
-
},
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
func init() {
|
|
282
|
-
serveCmd.Flags().IntP("port", "p", 8080, "Port to listen on")
|
|
283
|
-
rootCmd.AddCommand(serveCmd)
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
func main() {
|
|
287
|
-
rootCmd.Execute()
|
|
288
|
-
}
|
|
289
|
-
```
|
|
290
|
-
|
|
291
|
-
## 项目结构
|
|
292
|
-
|
|
293
|
-
```
|
|
294
|
-
myproject/
|
|
295
|
-
├── go.mod
|
|
296
|
-
├── go.sum
|
|
297
|
-
├── main.go
|
|
298
|
-
├── cmd/
|
|
299
|
-
│ └── myapp/
|
|
300
|
-
│ └── main.go
|
|
301
|
-
├── internal/
|
|
302
|
-
│ ├── handler/
|
|
303
|
-
│ ├── service/
|
|
304
|
-
│ └── repository/
|
|
305
|
-
├── pkg/
|
|
306
|
-
│ └── utils/
|
|
307
|
-
└── tests/
|
|
308
|
-
```
|
|
309
|
-
|
|
310
|
-
## 常用库
|
|
311
|
-
|
|
312
|
-
| 库 | 用途 |
|
|
313
|
-
|---|------|
|
|
314
|
-
| gin/echo | Web 框架 |
|
|
315
|
-
| gorm | ORM |
|
|
316
|
-
| cobra | CLI |
|
|
317
|
-
| viper | 配置 |
|
|
318
|
-
| zap/zerolog | 日志 |
|
|
319
|
-
| testify | 测试 |
|
|
320
|
-
| wire | 依赖注入 |
|
|
321
|
-
|
|
322
|
-
---
|
|
323
|
-
|
|
1
|
+
---
|
|
2
|
+
name: go
|
|
3
|
+
description: Go 开发。高并发、微服务、云原生、CLI工具。当用户提到 Go、Golang、Gin、Echo、goroutine 时使用。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 📜 符箓秘典 · Go
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
## Web 框架
|
|
10
|
+
|
|
11
|
+
### Gin
|
|
12
|
+
```go
|
|
13
|
+
package main
|
|
14
|
+
|
|
15
|
+
import (
|
|
16
|
+
"net/http"
|
|
17
|
+
"github.com/gin-gonic/gin"
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
type User struct {
|
|
21
|
+
ID int `json:"id"`
|
|
22
|
+
Name string `json:"name" binding:"required"`
|
|
23
|
+
Email string `json:"email" binding:"required,email"`
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
func main() {
|
|
27
|
+
r := gin.Default()
|
|
28
|
+
|
|
29
|
+
// 中间件
|
|
30
|
+
r.Use(gin.Logger())
|
|
31
|
+
r.Use(gin.Recovery())
|
|
32
|
+
|
|
33
|
+
// 路由组
|
|
34
|
+
api := r.Group("/api")
|
|
35
|
+
{
|
|
36
|
+
api.GET("/users/:id", getUser)
|
|
37
|
+
api.POST("/users", createUser)
|
|
38
|
+
api.PUT("/users/:id", updateUser)
|
|
39
|
+
api.DELETE("/users/:id", deleteUser)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
r.Run(":8080")
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
func getUser(c *gin.Context) {
|
|
46
|
+
id := c.Param("id")
|
|
47
|
+
c.JSON(http.StatusOK, gin.H{"id": id})
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
func createUser(c *gin.Context) {
|
|
51
|
+
var user User
|
|
52
|
+
if err := c.ShouldBindJSON(&user); err != nil {
|
|
53
|
+
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
c.JSON(http.StatusCreated, user)
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Echo
|
|
61
|
+
```go
|
|
62
|
+
package main
|
|
63
|
+
|
|
64
|
+
import (
|
|
65
|
+
"net/http"
|
|
66
|
+
"github.com/labstack/echo/v4"
|
|
67
|
+
"github.com/labstack/echo/v4/middleware"
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
func main() {
|
|
71
|
+
e := echo.New()
|
|
72
|
+
|
|
73
|
+
e.Use(middleware.Logger())
|
|
74
|
+
e.Use(middleware.Recover())
|
|
75
|
+
|
|
76
|
+
e.GET("/users/:id", getUser)
|
|
77
|
+
e.POST("/users", createUser)
|
|
78
|
+
|
|
79
|
+
e.Logger.Fatal(e.Start(":8080"))
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
func getUser(c echo.Context) error {
|
|
83
|
+
id := c.Param("id")
|
|
84
|
+
return c.JSON(http.StatusOK, map[string]string{"id": id})
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## 并发编程
|
|
89
|
+
|
|
90
|
+
### Goroutine & Channel
|
|
91
|
+
```go
|
|
92
|
+
package main
|
|
93
|
+
|
|
94
|
+
import (
|
|
95
|
+
"fmt"
|
|
96
|
+
"sync"
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
// 基础并发
|
|
100
|
+
func worker(id int, jobs <-chan int, results chan<- int) {
|
|
101
|
+
for j := range jobs {
|
|
102
|
+
results <- j * 2
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
func main() {
|
|
107
|
+
jobs := make(chan int, 100)
|
|
108
|
+
results := make(chan int, 100)
|
|
109
|
+
|
|
110
|
+
// 启动 worker
|
|
111
|
+
for w := 1; w <= 3; w++ {
|
|
112
|
+
go worker(w, jobs, results)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// 发送任务
|
|
116
|
+
for j := 1; j <= 9; j++ {
|
|
117
|
+
jobs <- j
|
|
118
|
+
}
|
|
119
|
+
close(jobs)
|
|
120
|
+
|
|
121
|
+
// 收集结果
|
|
122
|
+
for a := 1; a <= 9; a++ {
|
|
123
|
+
<-results
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// WaitGroup
|
|
128
|
+
func parallelFetch(urls []string) []string {
|
|
129
|
+
var wg sync.WaitGroup
|
|
130
|
+
results := make([]string, len(urls))
|
|
131
|
+
|
|
132
|
+
for i, url := range urls {
|
|
133
|
+
wg.Add(1)
|
|
134
|
+
go func(i int, url string) {
|
|
135
|
+
defer wg.Done()
|
|
136
|
+
results[i] = fetch(url)
|
|
137
|
+
}(i, url)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
wg.Wait()
|
|
141
|
+
return results
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Context 控制
|
|
145
|
+
func fetchWithTimeout(ctx context.Context, url string) (string, error) {
|
|
146
|
+
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
|
147
|
+
defer cancel()
|
|
148
|
+
|
|
149
|
+
req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
|
|
150
|
+
resp, err := http.DefaultClient.Do(req)
|
|
151
|
+
if err != nil {
|
|
152
|
+
return "", err
|
|
153
|
+
}
|
|
154
|
+
defer resp.Body.Close()
|
|
155
|
+
|
|
156
|
+
body, _ := io.ReadAll(resp.Body)
|
|
157
|
+
return string(body), nil
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## 错误处理
|
|
162
|
+
|
|
163
|
+
```go
|
|
164
|
+
package main
|
|
165
|
+
|
|
166
|
+
import (
|
|
167
|
+
"errors"
|
|
168
|
+
"fmt"
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
// 自定义错误
|
|
172
|
+
var ErrNotFound = errors.New("not found")
|
|
173
|
+
|
|
174
|
+
type ValidationError struct {
|
|
175
|
+
Field string
|
|
176
|
+
Message string
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
func (e *ValidationError) Error() string {
|
|
180
|
+
return fmt.Sprintf("%s: %s", e.Field, e.Message)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// 错误包装
|
|
184
|
+
func getUser(id int) (*User, error) {
|
|
185
|
+
user, err := db.FindUser(id)
|
|
186
|
+
if err != nil {
|
|
187
|
+
return nil, fmt.Errorf("getUser(%d): %w", id, err)
|
|
188
|
+
}
|
|
189
|
+
return user, nil
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// 错误检查
|
|
193
|
+
func handleUser(id int) error {
|
|
194
|
+
user, err := getUser(id)
|
|
195
|
+
if err != nil {
|
|
196
|
+
if errors.Is(err, ErrNotFound) {
|
|
197
|
+
return nil // 忽略未找到
|
|
198
|
+
}
|
|
199
|
+
return err
|
|
200
|
+
}
|
|
201
|
+
// 处理 user
|
|
202
|
+
return nil
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## 测试
|
|
207
|
+
|
|
208
|
+
```go
|
|
209
|
+
package main
|
|
210
|
+
|
|
211
|
+
import (
|
|
212
|
+
"testing"
|
|
213
|
+
"github.com/stretchr/testify/assert"
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
func TestAdd(t *testing.T) {
|
|
217
|
+
result := Add(1, 2)
|
|
218
|
+
assert.Equal(t, 3, result)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// 表驱动测试
|
|
222
|
+
func TestAddTable(t *testing.T) {
|
|
223
|
+
tests := []struct {
|
|
224
|
+
name string
|
|
225
|
+
a, b int
|
|
226
|
+
expected int
|
|
227
|
+
}{
|
|
228
|
+
{"positive", 1, 2, 3},
|
|
229
|
+
{"zero", 0, 0, 0},
|
|
230
|
+
{"negative", -1, 1, 0},
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
for _, tt := range tests {
|
|
234
|
+
t.Run(tt.name, func(t *testing.T) {
|
|
235
|
+
assert.Equal(t, tt.expected, Add(tt.a, tt.b))
|
|
236
|
+
})
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Benchmark
|
|
241
|
+
func BenchmarkAdd(b *testing.B) {
|
|
242
|
+
for i := 0; i < b.N; i++ {
|
|
243
|
+
Add(1, 2)
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
go test ./...
|
|
250
|
+
go test -v
|
|
251
|
+
go test -cover
|
|
252
|
+
go test -bench=.
|
|
253
|
+
go test -race # 竞态检测
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## CLI 工具
|
|
257
|
+
|
|
258
|
+
### Cobra
|
|
259
|
+
```go
|
|
260
|
+
package main
|
|
261
|
+
|
|
262
|
+
import (
|
|
263
|
+
"fmt"
|
|
264
|
+
"github.com/spf13/cobra"
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
var rootCmd = &cobra.Command{
|
|
268
|
+
Use: "myapp",
|
|
269
|
+
Short: "My CLI application",
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
var serveCmd = &cobra.Command{
|
|
273
|
+
Use: "serve",
|
|
274
|
+
Short: "Start the server",
|
|
275
|
+
Run: func(cmd *cobra.Command, args []string) {
|
|
276
|
+
port, _ := cmd.Flags().GetInt("port")
|
|
277
|
+
fmt.Printf("Starting server on port %d\n", port)
|
|
278
|
+
},
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
func init() {
|
|
282
|
+
serveCmd.Flags().IntP("port", "p", 8080, "Port to listen on")
|
|
283
|
+
rootCmd.AddCommand(serveCmd)
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
func main() {
|
|
287
|
+
rootCmd.Execute()
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## 项目结构
|
|
292
|
+
|
|
293
|
+
```
|
|
294
|
+
myproject/
|
|
295
|
+
├── go.mod
|
|
296
|
+
├── go.sum
|
|
297
|
+
├── main.go
|
|
298
|
+
├── cmd/
|
|
299
|
+
│ └── myapp/
|
|
300
|
+
│ └── main.go
|
|
301
|
+
├── internal/
|
|
302
|
+
│ ├── handler/
|
|
303
|
+
│ ├── service/
|
|
304
|
+
│ └── repository/
|
|
305
|
+
├── pkg/
|
|
306
|
+
│ └── utils/
|
|
307
|
+
└── tests/
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
## 常用库
|
|
311
|
+
|
|
312
|
+
| 库 | 用途 |
|
|
313
|
+
|---|------|
|
|
314
|
+
| gin/echo | Web 框架 |
|
|
315
|
+
| gorm | ORM |
|
|
316
|
+
| cobra | CLI |
|
|
317
|
+
| viper | 配置 |
|
|
318
|
+
| zap/zerolog | 日志 |
|
|
319
|
+
| testify | 测试 |
|
|
320
|
+
| wire | 依赖注入 |
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|