mirror of
https://github.com/shadowsocks/ShadowsocksX-NG.git
synced 2026-11-14 10:13:54 +00:00
build: add fail-fast validation task with retained evidence
This commit is contained in:
@@ -13,6 +13,8 @@
|
||||
|
||||
旧版工程源码已从本仓库移除,归档在 [shadowsocks/ShadowsocksX-NG](https://github.com/shadowsocks/ShadowsocksX-NG) 的 [`legacy-v1`](https://github.com/shadowsocks/ShadowsocksX-NG/tree/legacy-v1) 分支,仅供参考,不保证可构建;其功能说明与使用文档见 [legacy-v1 的 README](https://github.com/shadowsocks/ShadowsocksX-NG/blob/legacy-v1/README.md)。
|
||||
|
||||
构建与统一验证入口见 [`ShadowsocksX-NG2/README.md` 的「开发、构建与测试」](ShadowsocksX-NG2/README.md#开发构建与测试)。
|
||||
|
||||
## 开发钩子
|
||||
|
||||
新 clone 后,在仓库根目录启用 Git hooks:
|
||||
|
||||
@@ -79,6 +79,24 @@ ShadowsocksX-NG 的现代化重写版本。新工程的全部源码与构建配
|
||||
|
||||
## 开发、构建与测试
|
||||
|
||||
统一验证入口(从仓库根目录调用):
|
||||
|
||||
```bash
|
||||
task --exit-code --taskfile ShadowsocksX-NG2/Taskfile.dist.yml validate
|
||||
# 按指定顺序只运行所需关卡:
|
||||
task --exit-code --taskfile ShadowsocksX-NG2/Taskfile.dist.yml validate -- lint test
|
||||
```
|
||||
|
||||
在本目录内可用 `task --exit-code validate`。从任意目录可用 `task --exit-code --taskfile /path/to/ShadowsocksX-NG/ShadowsocksX-NG2/Taskfile.dist.yml validate`。入口按 Taskfile 所在位置定位工程目录,内部调用发行 Taskfile 中的单项任务。
|
||||
|
||||
默认按 `lint → test → test:smoke → build` 执行,也可按指定顺序选择子集,每关最多一次;任一关失败立即停止,后续关标记 `not_run`,进程返回非零。`--exit-code` 让 Task 透传关卡退出码;省略时 Task 仍返回非零,但可能使用自己的错误码。入口不自动重试,不修改测试并行设置,也不执行会修改源码的格式化。
|
||||
|
||||
每次运行创建独立的 `.build/validation/<UTC时间>-<随机后缀>/`,开始与结束均输出结果绝对路径。`summary.txt` 保存各关状态、退出码与证据状态;每个已执行关卡在同名子目录下保留合并 stdout/stderr 的 `raw.log` 和 `status.txt`(`test:smoke` 对应 `test-smoke/`),Xcode 关卡显式保存 `result.xcresult`。控制台只显示进度和摘要,需要完整错误时直接读取对应日志。所有产物均在现有忽略目录内;`task clean` 会删除它们,需要长期留存时先复制出去。
|
||||
|
||||
测试关通过本机 `xcrun xcresulttool get test-results summary` 和系统 `plutil` 尽力读取计数,无需新增脚本或工具依赖。`test-summary.json` 保存原始摘要,`test-summary.stderr.log` 保存 xcresulttool 错误,`count-reader.log` 保存计数读取错误。汇总展示通过、失败、跳过、预期失败及总数(Xcode 汇总口径,参数化测试的实际执行次数可能不同)。关卡与总体退出码由原命令决定,命令失败始终保留失败。结果包缺失或摘要不可读时显著标注 `evidence incomplete`(证据不完整)、计数未知,不改变命令结果,也不把缺失计数写成零。构建关不读取测试计数;未执行的关卡不等同于测试跳过。
|
||||
|
||||
统一入口成功表示所选关卡的命令通过,仍需核对证据是否完整;hostless、真实进程 smoke、原生 UI 和真实系统代理的验收边界仍分别成立,发布打包门槛见下文。
|
||||
|
||||
在本目录内,日常格式化、静态检查、工程生成、构建和测试优先使用 `Taskfile.dist.yml` 定义的任务:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -7,6 +7,103 @@ vars:
|
||||
DERIVED_DATA_DIR: "{{ .BUILD_DIR }}/derivedData"
|
||||
|
||||
tasks:
|
||||
validate:
|
||||
desc: 'Run validation gates in order and retain logs/results; stop on first failure'
|
||||
dir: '{{.TASKFILE_DIR}}'
|
||||
silent: true
|
||||
vars:
|
||||
GATES: '{{default "lint test test:smoke build" .CLI_ARGS | trim}}'
|
||||
RUN_DIR:
|
||||
sh: |
|
||||
mkdir -p {{.BUILD_DIR | shellQuote}}/validation
|
||||
mktemp -d {{.BUILD_DIR | shellQuote}}/validation/$(date -u +%Y%m%dT%H%M%SZ)-XXXXXX
|
||||
preconditions:
|
||||
- sh: '{{if regexMatch "^(lint|test|test:smoke|build)( (lint|test|test:smoke|build))*$" .GATES}}true{{else}}false{{end}}'
|
||||
msg: 'Choose validation gates: lint, test, test:smoke, build (space separated).'
|
||||
- sh: '{{if eq (len (splitList " " .GATES)) (len (uniq (splitList " " .GATES)))}}true{{else}}false{{end}}'
|
||||
msg: 'Choose each validation gate at most once.'
|
||||
cmds:
|
||||
- defer:
|
||||
task: validate:summary
|
||||
vars:
|
||||
RUN_DIR: '{{.RUN_DIR}}'
|
||||
GATES: '{{.GATES}}'
|
||||
CODE: '{{default "0" .EXIT_CODE}}'
|
||||
- "printf '%s\n' {{printf \"Validation results: %s\" .RUN_DIR | shellQuote}}"
|
||||
- for: {var: GATES, split: ' '}
|
||||
task: validate:gate
|
||||
vars:
|
||||
RUN_DIR: '{{.RUN_DIR}}'
|
||||
GATE: '{{.ITEM}}'
|
||||
|
||||
validate:gate:
|
||||
internal: true
|
||||
dir: '{{.TASKFILE_DIR}}'
|
||||
silent: true
|
||||
vars:
|
||||
GATE_DIR: '{{.RUN_DIR}}/{{.GATE | replace ":" "-"}}'
|
||||
cmds:
|
||||
- mkdir -p {{.GATE_DIR | shellQuote}}
|
||||
- defer:
|
||||
task: validate:result
|
||||
vars:
|
||||
GATE: '{{.GATE}}'
|
||||
GATE_DIR: '{{.GATE_DIR}}'
|
||||
CODE: '{{default "0" .EXIT_CODE}}'
|
||||
- "printf '%s\n' {{printf \"[%s] running; log: %s/raw.log\" .GATE .GATE_DIR | shellQuote}}"
|
||||
- >-
|
||||
task --exit-code --taskfile {{.TASKFILE_DIR | shellQuote}}/Taskfile.dist.yml {{.GATE | shellQuote}}
|
||||
RESULT_BUNDLE_PATH={{.GATE_DIR | shellQuote}}/result.xcresult
|
||||
> {{.GATE_DIR | shellQuote}}/raw.log 2>&1
|
||||
|
||||
validate:result:
|
||||
internal: true
|
||||
silent: true
|
||||
cmds:
|
||||
- |
|
||||
status=failed
|
||||
if [ {{.CODE | shellQuote}} = 0 ]; then status=passed; fi
|
||||
echo "[{{.GATE}}] $status; exit={{.CODE}}" > {{.GATE_DIR | shellQuote}}/status.txt
|
||||
- cmd: |
|
||||
{{if ne .GATE "lint"}}
|
||||
if [ ! -d {{.GATE_DIR | shellQuote}}/result.xcresult ]; then
|
||||
echo '[{{.GATE}}] evidence incomplete: result bundle missing; test counts unknown' >> {{.GATE_DIR | shellQuote}}/status.txt
|
||||
{{if ne .GATE "build"}}
|
||||
elif xcrun xcresulttool get test-results summary --path {{.GATE_DIR | shellQuote}}/result.xcresult > {{.GATE_DIR | shellQuote}}/test-summary.json 2> {{.GATE_DIR | shellQuote}}/test-summary.stderr.log; then
|
||||
if passed=$(plutil -extract passedTests raw -expect integer {{.GATE_DIR | shellQuote}}/test-summary.json) &&
|
||||
failed=$(plutil -extract failedTests raw -expect integer {{.GATE_DIR | shellQuote}}/test-summary.json) &&
|
||||
skipped=$(plutil -extract skippedTests raw -expect integer {{.GATE_DIR | shellQuote}}/test-summary.json) &&
|
||||
expected=$(plutil -extract expectedFailures raw -expect integer {{.GATE_DIR | shellQuote}}/test-summary.json) &&
|
||||
total=$(plutil -extract totalTestCount raw -expect integer {{.GATE_DIR | shellQuote}}/test-summary.json); then
|
||||
echo "[{{.GATE}}] tests: passed=$passed failed=$failed skipped=$skipped expectedFailures=$expected total=$total" >> {{.GATE_DIR | shellQuote}}/status.txt
|
||||
else
|
||||
printf '%s\n' "$passed" "$failed" "$skipped" "$expected" "$total" >> {{.GATE_DIR | shellQuote}}/count-reader.log
|
||||
echo '[{{.GATE}}] evidence incomplete: invalid test summary; test counts unknown (see count-reader.log)' >> {{.GATE_DIR | shellQuote}}/status.txt
|
||||
fi 2> {{.GATE_DIR | shellQuote}}/count-reader.log
|
||||
else
|
||||
echo '[{{.GATE}}] evidence incomplete: xcresulttool failed; test counts unknown (see test-summary.stderr.log)' >> {{.GATE_DIR | shellQuote}}/status.txt
|
||||
{{end}}
|
||||
fi
|
||||
{{end}}
|
||||
- cat {{.GATE_DIR | shellQuote}}/status.txt
|
||||
|
||||
validate:summary:
|
||||
internal: true
|
||||
silent: true
|
||||
cmds:
|
||||
- |
|
||||
echo 'Validation command exit={{.CODE}}' > {{.RUN_DIR | shellQuote}}/summary.txt
|
||||
echo 'Selected gates: {{.GATES}}' >> {{.RUN_DIR | shellQuote}}/summary.txt
|
||||
- for: {var: GATES, split: ' '}
|
||||
cmd: |
|
||||
if [ -f {{.RUN_DIR | shellQuote}}/{{.ITEM | replace ":" "-"}}/status.txt ]; then
|
||||
cat {{.RUN_DIR | shellQuote}}/{{.ITEM | replace ":" "-"}}/status.txt >> {{.RUN_DIR | shellQuote}}/summary.txt
|
||||
else
|
||||
echo '[{{.ITEM}}] not_run' >> {{.RUN_DIR | shellQuote}}/summary.txt
|
||||
fi
|
||||
- cat {{.RUN_DIR | shellQuote}}/summary.txt
|
||||
- "printf '%s\n' {{printf \"Summary: %s/summary.txt\" .RUN_DIR | shellQuote}}"
|
||||
|
||||
gen:prj:
|
||||
desc: 'Generate xcode project by xcodegen'
|
||||
cmds:
|
||||
@@ -24,6 +121,7 @@ tasks:
|
||||
-configuration Debug
|
||||
-destination 'platform=macOS,arch=arm64'
|
||||
-derivedDataPath {{ .DERIVED_DATA_DIR }}
|
||||
{{if .RESULT_BUNDLE_PATH}}-resultBundlePath {{.RESULT_BUNDLE_PATH | shellQuote}}{{end}}
|
||||
build
|
||||
|
||||
build:release:
|
||||
@@ -68,6 +166,7 @@ tasks:
|
||||
-scheme ShadowsocksX-NG2
|
||||
-destination 'platform=macOS,arch=arm64'
|
||||
-derivedDataPath {{ .DERIVED_DATA_DIR }}
|
||||
{{if .RESULT_BUNDLE_PATH}}-resultBundlePath {{.RESULT_BUNDLE_PATH | shellQuote}}{{end}}
|
||||
test
|
||||
|
||||
test:binaries:
|
||||
@@ -92,6 +191,7 @@ tasks:
|
||||
-scheme ShadowsocksX-NG2Smoke
|
||||
-destination 'platform=macOS,arch=arm64'
|
||||
-derivedDataPath {{ .DERIVED_DATA_DIR }}
|
||||
{{if .RESULT_BUNDLE_PATH}}-resultBundlePath {{.RESULT_BUNDLE_PATH | shellQuote}}{{end}}
|
||||
test
|
||||
|
||||
clean:
|
||||
|
||||
Reference in New Issue
Block a user