Repository navigation
Expand file tree
/
Copy pathTaskfile.yml
More file actions
413 lines (363 loc) · 14.6 KB
/
Copy pathTaskfile.yml
File metadata and controls
413 lines (363 loc) · 14.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
version: '3'
vars:
LOCALES_DIR: ./resources/locales
GO_MODULE: github.com/easysoft/gitfox-community
GOPROXY: 'https://goproxy.cn,direct'
GOSUMDB: sum.golang.google.cn
BIN_DIR: "{{.ROOT_DIR}}/bin"
UNIT_DIR: "{{.ROOT_DIR}}/unit"
GOOS: $(go env GOOS)
GOARCH: $(go env GOARCH)
BUILD_RELEASE:
sh: git rev-parse --abbrev-ref HEAD 2>/dev/null | sed 's|release/||' | grep -v '^$' || echo "0.0.1"
BUILD_DATE:
sh: date '+%Y-%m-%d %H:%M:%S'
GIT_BRANCH:
sh: git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown"
GIT_COMMIT:
sh: git rev-parse --short HEAD 2>/dev/null || echo "unknown"
VERSION_PKG: github.com/easysoft/gitfox-community/pkg/utils/common
LDFLAGS: "-w -s \
-X '{{.VERSION_PKG}}.Version={{.BUILD_RELEASE}}' \
-X '{{.VERSION_PKG}}.BuildDate={{.BUILD_DATE}}' \
-X '{{.VERSION_PKG}}.GitBranch={{.GIT_BRANCH}}' \
-X '{{.VERSION_PKG}}.GitCommitHash={{.GIT_COMMIT}}'"
PLATFORMS_ARCHS:
- os: linux
arches: [amd64, arm64] # Linux支持的架构
# - os: darwin
# arches: [amd64, arm64] # macOS支持的架构(Intel和M系列)
- os: windows
arches: [amd64] # Windows支持的架构
tasks:
# 默认任务
default:
desc: 显示所有可用任务
cmds:
- task --list
# 测试相关任务
test:service:
desc: "仅执行Service层单测"
vars:
UNIT_JSON_FILE: "{{.UNIT_DIR}}/ut_result.json"
JUNIT_REPORT_FILE: "{{.UNIT_DIR}}/junit-report.xml"
COVER_PROFILE_FILE: "{{.UNIT_DIR}}/coverage.out"
STATS_OUTPUT_FILE: "{{.UNIT_DIR}}/unit_stats.txt"
COVER_HTML_FILE: "{{.UNIT_DIR}}/coverage.html"
cmds:
# 步骤2:自动检测并安装 go-junit-report(核心新增逻辑)
- |
echo "🔍 检查 go-junit-report 工具是否安装..."
if ! command -v go-junit-report &> /dev/null; then
echo "⚠️ 未检测到 go-junit-report,开始自动安装..."
# 临时设置 GOPROXY 确保安装速度
GOPROXY=https://goproxy.cn,direct go install github.com/jstemmer/go-junit-report/v2@latest
# 验证安装是否成功
if ! command -v go-junit-report &> /dev/null; then
# 尝试手动添加 GOPATH/bin 到 PATH(避免安装后路径未生效)
export PATH="$PATH:$(go env GOPATH)/bin"
if ! command -v go-junit-report &> /dev/null; then
echo "❌ 安装 go-junit-report 失败!请手动执行:go install github.com/jstemmer/go-junit-report/v2@latest"
exit 1
fi
fi
echo "✅ go-junit-report 安装成功!"
else
echo "✅ go-junit-report 已安装,跳过安装步骤"
fi
# 步骤3:执行单测并生成 JSON/JUnit 日志
- |
mkdir -p {{.UNIT_DIR}} && \
cd "{{.ROOT_DIR}}/app/service" && \
echo "🚀 开始执行 service 单测..."
# 生成 JSON 日志(用于原生统计)
go test -v -json \
-coverpkg="github.com/easysoft/gitfox-community/app/service/..." \
-coverprofile="{{.COVER_PROFILE_FILE}}" \
-covermode=atomic \
./... > "{{.UNIT_JSON_FILE}}" 2>&1
# 生成 JUnit XML 报告(用于结构化统计)
cat "{{.UNIT_JSON_FILE}}" | go-junit-report -set-exit-code > "{{.JUNIT_REPORT_FILE}}" 2>&1
# 步骤4:解析 JUnit 报告统计用例结果
- |
cd "{{.ROOT_DIR}}/app/service" && \
echo -e "\n========================================"
echo " 📊 service 测试结果统计 "
echo "========================================"
# 安装 xmllint(若缺失,仅 Linux 需要)
if ! command -v xmllint &> /dev/null && [ "$(uname -s)" = "Linux" ]; then
echo "⚠️ 未检测到 xmllint,开始自动安装(仅Linux)..."
if [ -x "$(command -v apt)" ]; then
apt update && apt install -y libxml2-utils -qq > /dev/null
elif [ -x "$(command -v yum)" ]; then
yum install -y libxml2 -qq > /dev/null
else
echo "❌ 无法自动安装 xmllint,请手动安装后重试!"
exit 1
fi
echo "✅ xmllint 安装成功!"
fi
# 统计核心指标
TOTAL=$(xmllint --xpath 'count(//testcase)' "{{.JUNIT_REPORT_FILE}}" 2>/dev/null || echo 0)
FAILED=$(xmllint --xpath 'count(//failure) + count(//error)' "{{.JUNIT_REPORT_FILE}}" 2>/dev/null || echo 0)
PASSED=$((TOTAL - FAILED))
SKIPPED=$(xmllint --xpath 'count(//skipped)' "{{.JUNIT_REPORT_FILE}}" 2>/dev/null || echo 0)
# 计算通过率(避免除以0)
if [ $TOTAL -eq 0 ]; then
RATE="0.00%"
else
RATE=$(echo "scale=2; $PASSED / $TOTAL * 100" | bc 2>/dev/null || echo 0.00)
RATE="${RATE}%"
fi
echo -e "\n========================================"
echo " 📊 测试&覆盖率统计 "
echo "========================================"
echo "总用例: $TOTAL" | tee -a "{{.STATS_OUTPUT_FILE}}"
echo "成功数: $PASSED" | tee -a "{{.STATS_OUTPUT_FILE}}"
echo "失败数: $FAILED" | tee -a "{{.STATS_OUTPUT_FILE}}"
echo "跳过数: $SKIPPED" | tee -a "{{.STATS_OUTPUT_FILE}}"
echo "通过率: $RATE" | tee -a "{{.STATS_OUTPUT_FILE}}"
# 失败数非0则退出(适配 CI/CD)
if [ $FAILED -gt 0 ]; then
echo "❌ service 测试失败!失败用例数:$FAILED"
exit 1
else
echo "✅ service 所有用例测试通过!"
fi
- |
if [ -f "{{.COVER_PROFILE_FILE}}" ] && [ -s "{{.COVER_PROFILE_FILE}}" ]; then
echo "🚀 生成HTML覆盖率报告..."
go tool cover -html="{{.COVER_PROFILE_FILE}}" -o "{{.COVER_HTML_FILE}}"
echo "📄 HTML覆盖率报告已生成:{{.COVER_HTML_FILE}}"
else
echo "⚠️ 未生成有效覆盖率文件(无测试文件执行)"
fi
# 步骤2:解析覆盖率数据(核心)
- |
# 初始化覆盖率为0
TOTAL_COVERAGE="0.00%"
# 仅当覆盖率文件有效时计算
if [ -f "{{.COVER_PROFILE_FILE}}" ] && [ -s "{{.COVER_PROFILE_FILE}}" ]; then
# 精准提取total行 + 格式化数值(修复.6%→0.60%问题)
COVER_VALUE=$(go tool cover -func="{{.COVER_PROFILE_FILE}}" | \
grep -E "^total:" | awk '{print $3}' | sed 's/%//')
# 补零+保留两位小数
COVER_VALUE=$(echo "scale=2; $COVER_VALUE" | bc 2>/dev/null | awk '{printf "%.2f", $0}')
TOTAL_COVERAGE="${COVER_VALUE}%"
fi
# 仅输出整体覆盖率(核心需求)
echo "Service 整体覆盖率: $TOTAL_COVERAGE" | tee -a "{{.STATS_OUTPUT_FILE}}"
silent: false
test:clean:
desc: 清理单测输出文件
cmds:
- rm -rf {{.UNIT_DIR}}/*
test:coverage:
desc: 运行测试并生成覆盖率报告
cmds:
- go test -coverprofile=coverage.out ./...
- go tool cover -html=coverage.out -o coverage.html
- echo "覆盖率报告已生成 coverage.html"
# 代码质量检查
lint:
desc: 运行代码检查
cmds:
- golangci-lint run
fmt:
desc: 格式化代码
cmds:
- go fmt ./...
tidy:
desc: 清理未使用的依赖
cmds:
- go mod tidy
vet:
desc: 运行 go vet
cmds:
- go vet ./...
# 清理任务
clean:
desc: 清理构建文件
cmds:
- rm -rf {{.BIN_DIR}}/*
# 完整的检查流程
check:
desc: 运行完整的代码检查流程
deps: [fmt, vet, i18n:check, test]
cmds:
- echo "✅ 所有检查通过!"
# 发布前检查
pre-commit:
desc: 提交前检查
deps: [check]
cmds:
- echo "🚀 代码已准备好提交!"
build:
desc: 构建应用
deps: [clean] # 先执行清理
cmds:
- go build -o "{{.BIN_DIR}}/gitfox" -ldflags "{{.LDFLAGS}}" ./cmd/cli/main.go
- cp "{{$.ROOT_DIR}}/configs/prod.env" "{{.BIN_DIR}}/"
- cp "{{$.ROOT_DIR}}/configs/prod.yaml" "{{.BIN_DIR}}/"
- echo "本地构建完成,二进制文件位于 {{.BIN_DIR}}/gitfox"
cross-build:
desc: 交叉编译应用
deps: [clean] # 先执行清理
cmds:
- for: { var: PLATFORMS_ARCHS, as: item }
cmd: |
GOOS={{.item.os}}
{{range .item.arches}}
GOARCH={{.}}
BUILD_RELEASE={{$.BUILD_RELEASE}}
echo "编译: $GOOS/$GOARCH"
# 创建版本目录
DIST_DIR="{{$.BIN_DIR}}/$GOOS-$GOARCH"
mkdir -p "$DIST_DIR"
# windows 平台需要 .exe 后缀
suffix=""
if [ "$GOOS" = "windows" ]; then
suffix=".exe"
fi
# 执行交叉编译
CGO_ENABLED=0 GOOS=$GOOS GOARCH=$GOARCH \
go build -o "$DIST_DIR/gitfox"$suffix -ldflags "{{$.LDFLAGS}}" \
"{{$.ROOT_DIR}}/cmd/cli/main.go"
# 复制配置文件
cp "{{$.ROOT_DIR}}/configs/prod.env" "$DIST_DIR/"
cp "{{$.ROOT_DIR}}/configs/prod.yaml" "$DIST_DIR/"
# 压缩为 zip 文件
cd "{{$.BIN_DIR}}" && zip -r "$GOOS-$GOARCH.zip" "$GOOS-$GOARCH"
echo "完成: $GOOS-$GOARCH.zip"
{{end}}
parallel: true
docker:skip-deps:
internal: true
silent: true
cmds:
- "true"
docker:push:
desc: 构建多架构 Docker 镜像并推送至 hub.zentao.net(FORMAL=true 为正式包;SKIP_DEPS=true 跳过构建依赖)
deps:
- '{{if ne (default "false" .SKIP_DEPS) "true"}}cross-build{{else}}docker:skip-deps{{end}}'
- '{{if ne (default "false" .SKIP_DEPS) "true"}}download-ci-plugins{{else}}docker:skip-deps{{end}}'
preconditions:
- sh: test -f bin/linux-amd64/gitfox
msg: '缺少 bin/linux-amd64/gitfox(执行 task cross-build 或去掉 SKIP_DEPS=true)'
- sh: test -f bin/linux-arm64/gitfox
msg: '缺少 bin/linux-arm64/gitfox(执行 task cross-build 或去掉 SKIP_DEPS=true)'
- sh: test -f resources/ciPlugins/plugins.tar.gz
msg: '缺少 resources/ciPlugins/plugins.tar.gz(执行 task download-ci-plugins 或去掉 SKIP_DEPS=true)'
vars:
IMAGE:
sh: |
if [ "{{default "false" .FORMAL}}" = "true" ]; then
echo "hub.zentao.net/app/gitfox-server"
else
echo "hub.zentao.net/test/gitfox-server"
fi
DOCKER_TAG_DATE:
sh: date '+%Y%m%d'
TAG:
sh: |
FORMAL="{{default "false" .FORMAL}}"
if [ "$FORMAL" = "true" ]; then
echo "{{.BUILD_RELEASE}}" | tr '/' '-'
else
echo "{{.BUILD_RELEASE}}-{{.DOCKER_TAG_DATE}}" | tr '/' '-'
fi
PLATFORMS: 'linux/amd64,linux/arm64'
DOCKERFILE: 'deploy/Dockerfile'
BUILDER: 'multiarch'
cmds:
- docker buildx build --builder {{.BUILDER}} --platform {{.PLATFORMS}} -t {{.IMAGE}}:{{.TAG}} --push -f {{.DOCKERFILE}} .
- echo "已推送 {{.IMAGE}}:{{.TAG}} ({{.PLATFORMS}})"
docker:build:local:
desc: 本地构建 Docker 镜像(不推送,默认当前主机架构;SKIP_DEPS=true 跳过构建依赖)
deps:
- '{{if ne (default "false" .SKIP_DEPS) "true"}}cross-build{{else}}docker:skip-deps{{end}}'
- '{{if ne (default "false" .SKIP_DEPS) "true"}}download-ci-plugins{{else}}docker:skip-deps{{end}}'
preconditions:
- sh: test -f bin/linux-amd64/gitfox
msg: '缺少 bin/linux-amd64/gitfox(执行 task cross-build 或去掉 SKIP_DEPS=true)'
- sh: test -f resources/ciPlugins/plugins.tar.gz
msg: '缺少 resources/ciPlugins/plugins.tar.gz(执行 task download-ci-plugins 或去掉 SKIP_DEPS=true)'
vars:
IMAGE: 'gitfox-server'
DOCKER_TAG_DATE:
sh: date '+%Y%m%d'
TAG:
sh: |
if [ "{{.RELEASE}}" = "true" ]; then
echo "{{.BUILD_RELEASE}}" | tr '/' '-'
else
echo "{{.BUILD_RELEASE}}-{{.DOCKER_TAG_DATE}}" | tr '/' '-'
fi
PLATFORM: 'linux/amd64'
DOCKERFILE: 'deploy/Dockerfile'
BUILDER: 'multiarch'
cmds:
- docker buildx build --builder {{.BUILDER}} --platform {{.PLATFORM}} -t {{.IMAGE}}:{{.TAG}} --load -f {{.DOCKERFILE}} .
- echo "已构建本地镜像 {{.IMAGE}}:{{.TAG}} ({{.PLATFORM}})"
# 代码生成任务
wire:
desc: 生成 Wire 依赖注入代码
cmds:
- /bin/zsh cmd/cli/operations/server/wire.sh
sources:
- cmd/cli/operations/server/wire.go
- cmd/cli/operations/provider/*.go
generates:
- cmd/cli/operations/server/wire_gen.go
swagger:
desc: 生成 Swagger API 文档
cmds:
- |
if ! command -v swag &> /dev/null; then
echo "安装 swag 工具..."
go install github.com/swaggo/swag/cmd/swag@latest
fi
- swag init -g cmd/cli/main.go -o docs --parseDependency --parseInternal
- echo "✅ Swagger 文档已生成到 docs/ 目录"
sources:
- cmd/cli/main.go
- app/api/controller/**/*.go
- app/model/**/*.go
generates:
- docs/docs.go
- docs/swagger.json
- docs/swagger.yaml
# 多语言相关任务
i18n:generate:
desc: 检查多语言文件键值一致性,生成多语言键值常量
cmds:
- go run pkg/i18n/i18n-keygen/main.go -o pkg/i18n/i18n_keys.go {{.LOCALES_DIR}}
i18n:check:
desc: 仅检查多语言文件键值一致性
cmds:
- go run pkg/i18n/i18n-keygen/main.go -c {{.LOCALES_DIR}}
# 扫描规则验证任务
scanrule:check:
desc: 验证扫描规则的完整性(检查 types 和 rules 是否匹配,是否有重复)
dir: resources/scanrule
cmds:
- go run validator/validator.go validator/main.go -dir .
scanrule:check:plugin:
desc: 验证指定插件的扫描规则(用法:task scanrule:check:plugin PLUGIN=golangci-lint)
dir: resources/scanrule
cmds:
- go run validator/validator.go validator/main.go -dir . -plugin {{.PLUGIN}}
download-ci-plugins:
desc: download ci plugin(用法:task download-ci-plugins plugins=https://example.com/p.tar.gz)
vars:
PLUGINS_DEFAULT:
sh: sed -n 's/.*PluginsZipUrl.*default:"\([^"]*\)".*/\1/p' "{{.ROOT_DIR}}/pkg/config/config.go" | head -n1
cmds:
- mkdir -p resources/ciPlugins
- |
PLUGINS="{{default .PLUGINS_DEFAULT .plugins}}"
if [ -z "$PLUGINS" ]; then
echo "❌ 无法确定 plugins 下载地址:请传入 plugins=... 或检查 pkg/config/config.go" >&2
exit 1
fi
wget -O resources/ciPlugins/plugins.tar.gz "$PLUGINS"