f3a8a38acd
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
web-platform-ci / Standalone decision service (no cloud credentials) (pull_request) Has been cancelled
web-platform-ci / TypeScript, lint, unit, build (pull_request) Has been cancelled
web-platform-ci / Playwright E2E (pull_request) Has been cancelled
lekiwi-compatibility / cpu-compatibility (pull_request) Has been cancelled
集成同源 BYOK 会话隔离、精简模型设置、官方订阅入口和 HTTPS 发布运维;保留本地训练/调参与控制能力。同步 npm 版本及 CHANGELOG,记录公网真实 API 验收仍待用户凭据。
81 lines
2.9 KiB
Python
81 lines
2.9 KiB
Python
"""Package an explicit allowlist, never the working tree/.env/user assets wholesale."""
|
|
|
|
import argparse
|
|
import hashlib
|
|
import json
|
|
import re
|
|
import shutil
|
|
import tarfile
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("release")
|
|
args = parser.parse_args()
|
|
if not re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9_.-]{0,63}", args.release):
|
|
parser.error("invalid release")
|
|
output = ROOT / "build/website-deployment/bundles" / args.release
|
|
output.mkdir(parents=True, exist_ok=False)
|
|
|
|
def copy(source, target):
|
|
if source.is_symlink():
|
|
raise RuntimeError("symlinks not allowed in publish inputs")
|
|
target.parent.mkdir(parents=True, exist_ok=True)
|
|
shutil.copyfile(source, target)
|
|
|
|
for source in (ROOT / "decision_server").rglob("*"):
|
|
relative = source.relative_to(ROOT)
|
|
if (
|
|
source.is_file()
|
|
and "tests" not in relative.parts
|
|
and "__pycache__" not in relative.parts
|
|
and source.suffix in (".py", ".json", ".txt", ".md")
|
|
):
|
|
copy(source, output / "app" / relative)
|
|
copy(
|
|
ROOT / "contracts/lekiwi-agent-v1.schema.json",
|
|
output / "app/contracts/lekiwi-agent-v1.schema.json",
|
|
)
|
|
for source in (ROOT / "deploy/cadworld").iterdir():
|
|
if source.is_file():
|
|
copy(source, output / "deploy" / source.name)
|
|
copy(ROOT / "deploy/cadworld/Dockerfile", output / "app/Dockerfile")
|
|
copy(ROOT / "deploy/cadworld/.dockerignore", output / "app/.dockerignore")
|
|
copy(
|
|
ROOT / "deploy/cadworld/requirements.lock.txt",
|
|
output / "app/deploy/cadworld/requirements.lock.txt",
|
|
)
|
|
vendor = ROOT / "build/website-deployment/vendor"
|
|
for source in [
|
|
vendor / "codex",
|
|
vendor / "codex-origin.json",
|
|
*sorted((vendor / "wheels").glob("*.whl")),
|
|
]:
|
|
copy(source, output / "app/vendor" / source.relative_to(vendor))
|
|
for source in (ROOT / "website-dist").rglob("*"):
|
|
if source.is_file():
|
|
copy(source, output / "static" / source.relative_to(ROOT / "website-dist"))
|
|
if not (output / "static/index.html").exists() or (output / "static/tuning.html").exists():
|
|
raise RuntimeError("website production build required")
|
|
manifest = {
|
|
str(p.relative_to(output)): hashlib.sha256(p.read_bytes()).hexdigest()
|
|
for p in sorted(output.rglob("*"))
|
|
if p.is_file()
|
|
}
|
|
(output / "manifest.json").write_text(
|
|
json.dumps({"release": args.release, "files": manifest}, indent=2)
|
|
)
|
|
archive = output.with_suffix(".tar.gz")
|
|
with tarfile.open(archive, "w:gz") as tar:
|
|
for path in sorted(output.iterdir()):
|
|
tar.add(path, arcname=path.name)
|
|
print(str(archive))
|
|
print("sha256", hashlib.sha256(archive.read_bytes()).hexdigest())
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|