Files
Mujoco_WASM/deploy/cadworld/publish.sh
T
chenlin 0d986f60bd
web-platform-ci / Standalone decision service (no cloud credentials) (push) Has been cancelled
web-platform-ci / TypeScript, lint, unit, build (push) Has been cancelled
web-platform-ci / Playwright E2E (push) Has been cancelled
lekiwi-compatibility / cpu-compatibility (push) Has been cancelled
feat: release v1.0.2 LeKiwi 语言控制与网站嵌入
集成服务器托管模型、自然语言移动与有界抓放、内置 LeKiwi URL 导入和双摄像头;同步部署契约与指定域名 iframe 白名单,保留原有物理安全、会话及调用预算防护。

更新 npm 包及锁文件版本、CHANGELOG 与发布文档。提交前 typecheck、120 项定向前端测试和 44 项后端测试通过(3 项可选跳过);真实 v2 云模型抓放仍待单独验收,不包含运行密钥或构建产物。
2026-09-24 15:29:49 +08:00

71 lines
3.8 KiB
Bash

#!/usr/bin/env bash
# Run on the target host after baseline backup, image imports and TLS bootstrap.
set -euo pipefail
release=${1:?usage: publish.sh RELEASE}
[[ "$release" =~ ^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$ ]] || exit 2
root=/opt/cadworld-sim
www=/opt/1panel/apps/openresty/openresty/www
site=$www/sites/cadworld-sim.robotquan.com
nginx=1Panel-openresty-m72w
stage=$root/releases/$release
[[ -f "$stage/manifest.json" ]] || { echo 'missing verified release'; exit 1; }
python3 - "$stage" <<'PY'
import hashlib,json,pathlib,sys
root=pathlib.Path(sys.argv[1])
manifest=json.loads((root/'manifest.json').read_text())
for name,digest in manifest['files'].items():
path=root/name
if '..' in pathlib.Path(name).parts or pathlib.Path(name).is_absolute() or path.is_symlink():
raise RuntimeError('invalid manifest path')
if hashlib.sha256(path.read_bytes()).hexdigest()!=digest:
raise RuntimeError('artifact checksum mismatch: '+name)
print('Release manifest verified')
PY
old=''
[[ ! -f $root/current.txt ]] || read -r old < "$root/current.txt"
docker build --network none --pull=false -t "cadworld-decision:$release" "$stage/app"
# Fail before replacing the live service if a runtime contract/module was omitted.
# No server keys, network, volumes or inference are available to this check.
docker run --rm --network none --read-only --cap-drop ALL \
--security-opt no-new-privileges --entrypoint python "cadworld-decision:$release" \
-c 'import decision_server.web_server; from decision_server.language_tasks import resolve_target; assert resolve_target("B", [])[1] == "table"; print("Runtime imports and v2 contracts verified")'
# No current traffic is changed before the build and static manifest succeed.
mkdir -p "$site/releases/$release"
cp -a "$stage/static/." "$site/releases/$release/"
chmod -R a+rX "$site/releases/$release"
restore() {
trap - ERR
if [[ -n "$old" ]]; then
cp "$root/releases/$old/deploy/compose.yaml" "$root/compose.yaml"
cp "$root/releases/$old/deploy/openresty.conf" /opt/1panel/apps/openresty/openresty/conf/conf.d/cadworld-sim.robotquan.com.conf
printf 'CADWORLD_RELEASE=%s\n' "$old" > "$root/release.env"
docker compose --env-file "$root/release.env" -f "$root/compose.yaml" up -d --wait decision || true
ln -sfn "releases/$old" "$site/current.next"
mv -Tf "$site/current.next" "$site/current"
docker exec "$nginx" nginx -t && docker exec "$nginx" nginx -s reload || true
else
docker compose --env-file "$root/release.env" -f "$root/compose.yaml" stop decision || true
conf=/opt/1panel/apps/openresty/openresty/conf/conf.d/cadworld-sim.robotquan.com.conf
[[ ! -f "$conf" ]] || mv "$conf" "$root/failed-first-vhost.conf"
docker exec "$nginx" nginx -t && docker exec "$nginx" nginx -s reload || true
fi
echo 'Publish failed; previous deployment retained/restored. Inspect logs before retry.' >&2
exit 1
}
trap restore ERR
cp "$stage/deploy/compose.yaml" "$root/compose.yaml"
printf 'CADWORLD_RELEASE=%s\n' "$release" > "$root/release.env"
docker compose --env-file "$root/release.env" -f "$root/compose.yaml" up -d --wait --wait-timeout 75 decision
curl --fail --silent --show-error --max-time 5 -H 'Host: cadworld-sim.robotquan.com' http://127.0.0.1:8768/healthz
ln -sfn "releases/$release" "$site/current.next"
mv -Tf "$site/current.next" "$site/current"
cp "$stage/deploy/openresty.conf" /opt/1panel/apps/openresty/openresty/conf/conf.d/cadworld-sim.robotquan.com.conf
docker exec "$nginx" nginx -t
docker exec "$nginx" nginx -s reload
curl --fail --silent --show-error --max-time 15 https://cadworld-sim.robotquan.com/ -o /dev/null
printf '%s\n' "$old" > "$root/previous.txt"
printf '%s\n' "$release" > "$root/current.txt"
docker image inspect "cadworld-decision:$release" --format '{{.Id}}' > "$stage/image-id.txt"
trap - ERR
echo "Published $release; previous=$old"