Skip to content

Commit 5951b1e

Browse files
committed
feat: scaffold automation pack candidate
1 parent a607dd8 commit 5951b1e

6 files changed

Lines changed: 226 additions & 1 deletion

File tree

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
- `stateful``Godot State Charts`
1414
- `juice``Sparkle Lite`
1515

16+
另外保留一个**候选**方向:
17+
18+
- `packs/automation/``GodotE2E` 候选 PoC 骨架,当前**不在** `packs.manifest.json`,也**不参与**默认 bootstrap
19+
1620
## 设计原则
1721

1822
- 默认只启用适合自动化和 CI 的基线能力。
@@ -41,6 +45,7 @@
4145
- `packs/`:可选插件 pack
4246
- `scripts/bootstrap_toolbox_project.sh`:按 pack 组装新项目
4347
- `scripts/verify_bootstrap_flow.sh`:验证真实产物链路,覆盖 bootstrap、headless import 和 `gdUnit4` smoke
48+
- `scripts/verify_automation_pack_poc.sh`:验证 `packs/automation/` 候选 PoC 骨架,不接入默认验证链
4449
- `scripts/import_plugin_from_upstream.sh`:首次从 upstream 导入插件子树
4550
- `scripts/update_plugin_from_upstream.sh`:基于 lock 文件升级已纳入插件
4651
- `scripts/verify_toolbox_layout.sh`:校验工具箱布局
@@ -84,6 +89,14 @@ bash ./scripts/verify_bootstrap_flow.sh
8489

8590
CI 也跑同一条真实产物链。当前 workflow 固定使用官方 Linux 构建的 Godot `4.6.2`,本地建议保持 `4.6.x`,如果本机 Godot 不在 `PATH`,可通过 `GODOT_BIN=/path/to/godot` 显式指定。
8691

92+
候选 `automation` PoC 走独立入口:
93+
94+
```bash
95+
bash ./scripts/verify_automation_pack_poc.sh
96+
```
97+
98+
这个脚本只验证候选骨架和最小 bootstrap 前提,不会把 `automation` 接到默认 pack 清单里。
99+
87100
## 维护工具箱
88101

89102
首次纳入一个 git upstream 插件:

docs/maintenance-workflow.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,11 @@
3535
4. 它的升级与维护成本是否可控?
3636
5. 它是否能通过本地脚本验证,而不是只能靠编辑器手工点击?
3737

38-
结论只有 4 种:
38+
结论只有 5 种:
3939

4040
- 进入 `base`
4141
- 进入某个 `pack`
42+
- 先作为候选 `pack / PoC`
4243
- 只保留为外部参考
4344
- 暂不纳入
4445

@@ -61,6 +62,16 @@
6162
- 可以按项目需要叠加
6263
- 不会接管项目核心真相
6364

65+
### 候选 `pack / PoC`
66+
67+
如果方向值得继续,但还不适合进入 `packs.manifest.json`,先按候选 PoC 处理:
68+
69+
- 目录可以先放在 `packs/<name>/`
70+
- 必须明确标注“未纳入正式 pack”
71+
- 不修改默认 `bootstrap` 行为
72+
- 不接入默认验证链
73+
- 通过独立验证脚本证明这条路径值得继续
74+
6475
## B. 首次导入上游插件
6576

6677
首次导入时,按下面流程执行:
@@ -171,6 +182,12 @@ python3 -m json.tool upstreams.lock.json >/dev/null
171182
bash ./scripts/verify_bootstrap_flow.sh
172183
```
173184

185+
如果本轮改动的是候选 `automation` PoC,再补:
186+
187+
```bash
188+
bash ./scripts/verify_automation_pack_poc.sh
189+
```
190+
174191
如果本轮改动涉及 `import/update`,还应补:
175192

176193
```bash

packs/automation/README.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Automation Candidate Pack
2+
3+
这是 `GodotE2E` 方向的候选 pack / PoC 骨架,不是已经纳入的正式 pack。
4+
5+
当前约束:
6+
7+
- **不在** `packs.manifest.json`
8+
- **不参与** 默认 `bootstrap` 行为
9+
- **不接入** 当前默认 CI / 默认验证链
10+
11+
这个目录的目标是先把 E2E 自动化方向的最小骨架和评估入口固定下来,等上游安装方式、Python 包名、Godot 侧接入面都验证清楚后,再决定是否晋升成正式 pack。
12+
13+
## 当前内容
14+
15+
- `python/requirements-e2e.txt`
16+
Python 侧依赖占位。当前故意不锁定真实包名,避免把未经确认的安装名写进仓库。
17+
- `examples/tests/test_ui_smoke_placeholder.py`
18+
一个最小占位测试骨架,只表达未来 E2E 测试的大致入口,不代表已可执行。
19+
20+
## 当前缺口
21+
22+
1. 锁定真实的 `GodotE2E` Python 包名、安装方式和版本策略
23+
2. 确认是否需要 vendoring Godot 侧 addon,以及应落在哪个目录
24+
3. 定义最小可接受的 PoC 成功标准
25+
4. 决定通过什么条件把它晋升为正式 `pack`
26+
27+
## 本地验证
28+
29+
独立验证入口:
30+
31+
```bash
32+
bash ./scripts/verify_automation_pack_poc.sh
33+
```
34+
35+
这个脚本会:
36+
37+
- bootstrap 一个**不叠加 automation** 的最小临时项目
38+
- 校验候选骨架文件是否齐全
39+
- 在条件满足时执行最小占位验证
40+
- 输出当前 PoC 还缺什么
41+
42+
它不会修改当前默认验证链。
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
"""Candidate PoC placeholder for future GodotE2E smoke coverage."""
2+
3+
from __future__ import annotations
4+
5+
import os
6+
from pathlib import Path
7+
import unittest
8+
9+
10+
class AutomationPackPlaceholderTest(unittest.TestCase):
11+
def test_candidate_pack_not_yet_wired(self) -> None:
12+
project_root = os.environ.get("GODOT_PROJECT_ROOT")
13+
if not project_root:
14+
self.skipTest(
15+
"Candidate PoC only: set GODOT_PROJECT_ROOT after locking the real "
16+
"GodotE2E package name and runtime contract."
17+
)
18+
19+
self.assertTrue(Path(project_root).exists())
20+
self.skipTest(
21+
"Candidate PoC only: replace this placeholder once the real GodotE2E "
22+
"integration path is validated."
23+
)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Candidate PoC placeholder only.
2+
#
3+
# Do not add an unverified GodotE2E package name here.
4+
# The next maintainer should first confirm:
5+
# 1. the real Python package/install command
6+
# 2. whether version pinning belongs in this file or a separate lock file
7+
# 3. how the Python side coordinates with any Godot-side addon
8+
#
9+
# Expected follow-up:
10+
# - validate upstream install instructions
11+
# - lock the real package name and version
12+
# - add a minimal, actually runnable E2E smoke test
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
5+
KEEP_TEMP="0"
6+
TMP_ROOT="${TMPDIR:-/tmp}"
7+
WORKDIR=""
8+
9+
usage() {
10+
cat <<'EOF'
11+
Usage:
12+
bash ./scripts/verify_automation_pack_poc.sh [--keep-temp]
13+
14+
What it does:
15+
- bootstraps a minimal project without the candidate automation pack
16+
- checks that the candidate PoC scaffold exists
17+
- runs a minimal placeholder validation when Python is available
18+
- prints the current gaps before this PoC can graduate into a real pack
19+
EOF
20+
}
21+
22+
log() {
23+
printf '[verify-automation-poc] %s\n' "$*"
24+
}
25+
26+
die() {
27+
printf '[verify-automation-poc] ERROR: %s\n' "$*" >&2
28+
exit 1
29+
}
30+
31+
for arg in "$@"; do
32+
case "$arg" in
33+
--keep-temp)
34+
KEEP_TEMP="1"
35+
;;
36+
-h|--help)
37+
usage
38+
exit 0
39+
;;
40+
*)
41+
die "unexpected argument: ${arg}"
42+
;;
43+
esac
44+
done
45+
46+
cleanup() {
47+
if [[ -n "${WORKDIR}" && -d "${WORKDIR}" ]]; then
48+
if [[ "${KEEP_TEMP}" == "1" ]]; then
49+
log "kept temporary project at ${WORKDIR}"
50+
else
51+
rm -rf "${WORKDIR}"
52+
fi
53+
fi
54+
}
55+
56+
trap cleanup EXIT
57+
58+
require_file() {
59+
local path="$1"
60+
[[ -f "${path}" ]] || die "required file missing: ${path}"
61+
}
62+
63+
assert_manifest_lacks_automation() {
64+
if command -v jq >/dev/null 2>&1; then
65+
if jq -e '.packs[] | select(.id == "automation")' "${REPO_ROOT}/packs.manifest.json" >/dev/null; then
66+
die "candidate automation pack unexpectedly appears in packs.manifest.json"
67+
fi
68+
return 0
69+
fi
70+
71+
if grep -q '"id"[[:space:]]*:[[:space:]]*"automation"' "${REPO_ROOT}/packs.manifest.json"; then
72+
die "candidate automation pack unexpectedly appears in packs.manifest.json"
73+
fi
74+
}
75+
76+
require_file "${REPO_ROOT}/packs/automation/README.md"
77+
require_file "${REPO_ROOT}/packs/automation/python/requirements-e2e.txt"
78+
require_file "${REPO_ROOT}/packs/automation/examples/tests/test_ui_smoke_placeholder.py"
79+
assert_manifest_lacks_automation
80+
81+
WORKDIR="$(mktemp -d "${TMP_ROOT%/}/godot-toolbox-automation-poc.XXXXXX")"
82+
83+
log "bootstrapping minimal temporary project at ${WORKDIR}"
84+
bash "${REPO_ROOT}/scripts/bootstrap_toolbox_project.sh" "${WORKDIR}"
85+
86+
require_file "${WORKDIR}/godot/project.godot"
87+
require_file "${WORKDIR}/scripts/gdunit4_smoke.sh"
88+
89+
if [[ -f "${WORKDIR}/.toolbox-packs" ]]; then
90+
if [[ -n "$(tr -d '[:space:]' < "${WORKDIR}/.toolbox-packs")" ]]; then
91+
die "expected no packs in minimal bootstrap, found: $(cat "${WORKDIR}/.toolbox-packs")"
92+
fi
93+
fi
94+
95+
if command -v python3 >/dev/null 2>&1; then
96+
log "running placeholder Python validation"
97+
PLACEHOLDER_PYC="${TMP_ROOT%/}/godot-toolbox-automation-placeholder.pyc"
98+
rm -f "${PLACEHOLDER_PYC}"
99+
python3 - <<PY
100+
import py_compile
101+
py_compile.compile(
102+
r"${REPO_ROOT}/packs/automation/examples/tests/test_ui_smoke_placeholder.py",
103+
cfile=r"${PLACEHOLDER_PYC}",
104+
doraise=True,
105+
)
106+
PY
107+
rm -f "${PLACEHOLDER_PYC}"
108+
else
109+
log "python3 not found; skipped placeholder Python validation"
110+
fi
111+
112+
log "candidate pack remains intentionally outside packs.manifest.json and default bootstrap"
113+
log "current gaps:"
114+
log "1. lock the real GodotE2E Python package name and version strategy"
115+
log "2. decide whether a Godot-side addon must be vendored for this pack"
116+
log "3. define the minimal runnable E2E smoke contract for CI"
117+
log "4. set promotion criteria before adding automation to packs.manifest.json"
118+
log "PASS"

0 commit comments

Comments
 (0)