Files
AstrBot/scripts/hatch_build.py
LIghtJUNction dcaaf6286a test: comprehensive test coverage and type fixes
- Add 100+ new test files covering provider sources, platform adapters,
  agent runners, star/plugin system, knowledge base, core utils,
  pipeline, computer tools, builtin commands, and dashboard routes
- Fix Python type errors in sqlite.py (col() wrappers for SQLModel),
  astr_agent_tool_exec, core_lifecycle, star context/manager
- Fix TypeScript strict mode errors across 30+ dashboard Vue files
- Add import smoke tests, auth roundtrip, startup tests
- Add compile-all check and CLI entry test for AUR compatibility
- Restore BotMessageAccumulator and helpers lost in merge
2026-04-29 06:29:56 +08:00

101 lines
3.8 KiB
Python

"""Custom Hatchling build hook.
Only runs when the environment variable ASTRBOT_BUILD_DASHBOARD=1 is set,
so that `uv sync` / editable installs are never affected.
Usage:
ASTRBOT_BUILD_DASHBOARD=1 uv build
When enabled, this hook:
1. Runs `npm run build` inside the `dashboard/` directory.
2. Copies the resulting `dashboard/dist/` tree into
`astrbot/dashboard/dist/` so the static assets are shipped
inside the Python wheel.
"""
import os
import shutil
import subprocess
from logging import getLogger
from pathlib import Path
from typing import Any
from hatchling.builders.hooks.plugin.interface import BuildHookInterface
logger = getLogger(__name__)
class CustomBuildHook(BuildHookInterface):
PLUGIN_NAME = "custom"
def initialize(self, version: str, build_data: dict[str, Any]) -> None:
root = Path(self.root)
dashboard_src = root / "dashboard"
dist_src = dashboard_src / "dist"
dist_target = root / "astrbot" / "dashboard" / "dist"
if os.environ.get("ASTRBOT_BUILD_DASHBOARD", "").strip() != "1":
# Ensure the target directory and a placeholder exist so the wheel
# build does not fail when artifacts = ["..."] is declared.
# Handle the case where dist_target might be a broken symlink (e.g. in AUR builds)
if dist_target.is_symlink() or dist_target.is_file():
dist_target.unlink()
dist_target.mkdir(parents=True, exist_ok=True)
if not any(dist_target.iterdir()):
placeholder = dist_target / ".placeholder"
placeholder.write_text("# dashboard placeholder\n")
return
if not dashboard_src.exists():
logger.warning(
"[hatch_build] 'dashboard/' directory not found: skipping dashboard build."
)
if dist_target.is_symlink() or dist_target.is_file():
dist_target.unlink()
dist_target.mkdir(parents=True, exist_ok=True)
placeholder = dist_target / ".placeholder"
placeholder.write_text("# dashboard placeholder\n")
return
# ── Install Node dependencies if node_modules is absent ─────────────
if not (dashboard_src / "node_modules").exists():
logger.info("[hatch_build] Installing dashboard Node dependencies...")
subprocess.run(
["npm", "install"],
cwd=dashboard_src,
check=True,
)
# ── Build the Vue/Vite dashboard ──────────────────────────────────────
logger.info("[hatch_build] Building Vue dashboard (npm run build)...")
subprocess.run(
["npm", "run", "build"],
cwd=dashboard_src,
check=True,
)
if not dist_src.exists():
logger.warning(
"[hatch_build] dashboard/dist not found after build: skipping copy."
)
if dist_target.is_symlink() or dist_target.is_file():
dist_target.unlink()
dist_target.mkdir(parents=True, exist_ok=True)
placeholder = dist_target / ".placeholder"
placeholder.write_text("# dashboard placeholder\n")
return
# ── Copy into the Python package tree ───────────────────────────────
if dist_target.is_symlink() or dist_target.is_file():
dist_target.unlink()
elif dist_target.exists():
shutil.rmtree(dist_target)
shutil.copytree(dist_src, dist_target)
logger.info(
f"[hatch_build] Dashboard dist copied → {dist_target.relative_to(root)}"
)