feat: complete 2.0.7.12 platform overhaul
This commit is contained in:
@@ -7,6 +7,15 @@ param(
|
||||
$ErrorActionPreference = "Stop"
|
||||
$Root = Resolve-Path (Join-Path $PSScriptRoot "..")
|
||||
$Out = Join-Path $Root $OutDir
|
||||
$ExistingAdminMetadata = Join-Path $Root "web\admin\dist\admin-build.json"
|
||||
$AdminBuildId = if ($env:YMHUT_ADMIN_BUILD_ID) {
|
||||
$env:YMHUT_ADMIN_BUILD_ID
|
||||
} elseif ($SkipFrontend -and (Test-Path $ExistingAdminMetadata)) {
|
||||
(Get-Content $ExistingAdminMetadata -Raw | ConvertFrom-Json).buildId
|
||||
} else {
|
||||
"$Version-$([DateTimeOffset]::UtcNow.ToUnixTimeSeconds())"
|
||||
}
|
||||
$env:YMHUT_ADMIN_BUILD_ID = $AdminBuildId
|
||||
$env:GOPROXY = if ($env:YMHUT_GOPROXY) { $env:YMHUT_GOPROXY } elseif ($env:GOPROXY) { $env:GOPROXY } else { "https://goproxy.io,https://mirrors.aliyun.com/goproxy,direct" }
|
||||
|
||||
function Run-Step {
|
||||
@@ -39,6 +48,8 @@ if (-not $SkipFrontend) {
|
||||
}
|
||||
}
|
||||
|
||||
Run-Step (Join-Path $Root "web\admin") "npm" @("run", "validate:build")
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $Out | Out-Null
|
||||
|
||||
function Copy-IfExists {
|
||||
@@ -79,7 +90,7 @@ foreach ($Target in $Targets) {
|
||||
$env:GOARCH = $Target.GOARCH
|
||||
$env:CGO_ENABLED = "0"
|
||||
$Output = Join-Path $Out $Target.Name
|
||||
Run-Step $Root "go" @("build", "-tags", "embed_web", "-buildvcs=false", "-trimpath", "-ldflags", "-s -w -X ymhut-box/server/unified-management/internal/config.Version=$Version", "-o", $Output, ".\cmd\unified-management")
|
||||
Run-Step $Root "go" @("build", "-tags", "embed_web", "-buildvcs=false", "-trimpath", "-ldflags", "-s -w -X ymhut-box/server/unified-management/internal/config.Version=$Version -X ymhut-box/server/unified-management/internal/config.AdminBuildID=$AdminBuildId", "-o", $Output, ".\cmd\unified-management")
|
||||
}
|
||||
|
||||
Remove-Item Env:\GOOS -ErrorAction SilentlyContinue
|
||||
|
||||
@@ -6,6 +6,14 @@ OUT_DIR="${OUT_DIR:-dist-release}"
|
||||
SKIP_FRONTEND="${SKIP_FRONTEND:-0}"
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
OUT="$ROOT/$OUT_DIR"
|
||||
if [[ -n "${YMHUT_ADMIN_BUILD_ID:-}" ]]; then
|
||||
ADMIN_BUILD_ID="$YMHUT_ADMIN_BUILD_ID"
|
||||
elif [[ "$SKIP_FRONTEND" == "1" && -f "$ROOT/web/admin/dist/admin-build.json" ]]; then
|
||||
ADMIN_BUILD_ID="$(node -e "const fs=require('fs');process.stdout.write(JSON.parse(fs.readFileSync(process.argv[1],'utf8')).buildId||'')" "$ROOT/web/admin/dist/admin-build.json")"
|
||||
else
|
||||
ADMIN_BUILD_ID="$VERSION-$(date -u +%s)"
|
||||
fi
|
||||
export YMHUT_ADMIN_BUILD_ID="$ADMIN_BUILD_ID"
|
||||
export GOPROXY="${YMHUT_GOPROXY:-${GOPROXY:-https://goproxy.io,https://mirrors.aliyun.com/goproxy,direct}}"
|
||||
|
||||
(cd "$ROOT" && go mod download all && go mod verify)
|
||||
@@ -20,6 +28,8 @@ if [[ "$SKIP_FRONTEND" != "1" ]]; then
|
||||
done
|
||||
fi
|
||||
|
||||
(cd "$ROOT/web/admin" && npm run validate:build)
|
||||
|
||||
mkdir -p "$OUT"
|
||||
|
||||
copy_if_exists() {
|
||||
@@ -50,7 +60,7 @@ build_target() {
|
||||
local name="$3"
|
||||
(cd "$ROOT" && \
|
||||
GOOS="$goos" GOARCH="$goarch" CGO_ENABLED=0 \
|
||||
go build -tags embed_web -buildvcs=false -trimpath -ldflags "-s -w -X ymhut-box/server/unified-management/internal/config.Version=$VERSION" \
|
||||
go build -tags embed_web -buildvcs=false -trimpath -ldflags "-s -w -X ymhut-box/server/unified-management/internal/config.Version=$VERSION -X ymhut-box/server/unified-management/internal/config.AdminBuildID=$ADMIN_BUILD_ID" \
|
||||
-o "$OUT/$name" ./cmd/unified-management)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import { readFile, stat } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import process from "node:process";
|
||||
|
||||
const root = path.resolve(process.argv[2] || "web/admin/dist");
|
||||
|
||||
function resolveOutput(name) {
|
||||
const normalized = String(name || "").replaceAll("\\", "/");
|
||||
if (!normalized || normalized.startsWith("/") || normalized.split("/").includes("..")) {
|
||||
throw new Error(`Invalid asset path in manifest: ${JSON.stringify(name)}`);
|
||||
}
|
||||
const resolved = path.resolve(root, ...normalized.split("/"));
|
||||
if (resolved !== root && !resolved.startsWith(`${root}${path.sep}`)) {
|
||||
throw new Error(`Asset path escapes dist: ${JSON.stringify(name)}`);
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
|
||||
async function requireFile(name) {
|
||||
const file = resolveOutput(name);
|
||||
const info = await stat(file);
|
||||
if (!info.isFile() || info.size === 0) {
|
||||
throw new Error(`Missing or empty admin asset: ${name}`);
|
||||
}
|
||||
}
|
||||
|
||||
const manifest = JSON.parse(await readFile(path.join(root, "asset-manifest.json"), "utf8"));
|
||||
const build = JSON.parse(await readFile(path.join(root, "admin-build.json"), "utf8"));
|
||||
|
||||
if (!build.buildId || typeof build.buildId !== "string") {
|
||||
throw new Error("admin-build.json does not contain a buildId");
|
||||
}
|
||||
if (!manifest || typeof manifest !== "object" || Object.keys(manifest).length === 0) {
|
||||
throw new Error("asset-manifest.json is empty");
|
||||
}
|
||||
|
||||
await requireFile("index.html");
|
||||
for (const [key, entry] of Object.entries(manifest)) {
|
||||
if (!entry?.file) throw new Error(`Manifest entry ${key} has no output file`);
|
||||
for (const dependency of [...(entry.imports || []), ...(entry.dynamicImports || [])]) {
|
||||
if (!manifest[dependency]) throw new Error(`Manifest entry ${key} references missing entry ${dependency}`);
|
||||
}
|
||||
for (const file of [entry.file, ...(entry.css || []), ...(entry.assets || [])]) {
|
||||
await requireFile(file);
|
||||
}
|
||||
}
|
||||
|
||||
process.stdout.write(`Admin build ${build.buildId}: ${Object.keys(manifest).length} manifest entries verified.\n`);
|
||||
Reference in New Issue
Block a user