build(release): 加固 v0.1.0 桌面发布链路 (#3)
Client Quality Gates / Shared client and Web (push) Has been cancelled
Client Quality Gates / macOS Desktop (push) Has been cancelled

This commit is contained in:
chengchengzhou7
2026-07-17 09:36:16 +08:00
committed by GitHub
parent 1837ceff58
commit 4863ade45b
16 changed files with 895 additions and 323 deletions
+42 -1
View File
@@ -1,8 +1,10 @@
import { execFileSync } from "node:child_process";
import { readFile } from "node:fs/promises";
import { resolve } from "node:path";
import { fileURLToPath } from "node:url";
const frontendDir = fileURLToPath(new URL("../", import.meta.url));
const rootDir = resolve(frontendDir, "..");
const packageInfo = JSON.parse(await readFile(resolve(frontendDir, "package.json"), "utf8"));
const failures = [];
@@ -16,6 +18,8 @@ const commit = env.VITE_BUILD_COMMIT || "local";
const isCi = env.CI === "true" || env.GITHUB_ACTIONS === "true";
const isTagBuild = env.GITHUB_REF_TYPE === "tag";
const isReleaseBuild = env.RELEASE_BUILD === "true" || isTagBuild || channel === "release";
const requiresMacosSigning = env.REQUIRE_DESKTOP_SIGNING === "true";
const requiresWindowsSigning = env.REQUIRE_WINDOWS_SIGNING === "true";
const fail = (message) => failures.push(message);
const assert = (condition, message) => {
@@ -26,6 +30,18 @@ const requireEnv = (name) => {
assert(Boolean(env[name]), `${name} must be configured for signed desktop release builds.`);
};
const gitHead = () => {
try {
return execFileSync("git", ["rev-parse", "HEAD"], {
cwd: rootDir,
encoding: "utf8",
stdio: ["ignore", "pipe", "ignore"],
}).trim();
} catch {
return undefined;
}
};
assert(allowedChannels.has(channel), `VITE_BUILD_CHANNEL must be one of ${[...allowedChannels].join(", ")}.`);
if (isCi || isReleaseBuild) {
@@ -40,12 +56,25 @@ if (env.GITHUB_SHA) {
);
}
if (isReleaseBuild && fullShaPattern.test(commit)) {
const headSha = gitHead();
assert(Boolean(headSha), "Release builds must be able to resolve the current Git commit.");
if (headSha) {
assert(commit === headSha, "VITE_BUILD_COMMIT must match the current Git HEAD for release builds.");
}
}
if (isTagBuild) {
assert(env.GITHUB_REF_NAME === semverTag, `Release tag must be ${semverTag}; found ${env.GITHUB_REF_NAME || "<missing>"}.`);
assert(channel === "release", "Release tag builds must set VITE_BUILD_CHANNEL=release.");
}
if (env.REQUIRE_DESKTOP_SIGNING === "true") {
assert(
!(requiresMacosSigning && requiresWindowsSigning),
"macOS and Windows signing requirements must be checked in their native jobs.",
);
if (requiresMacosSigning) {
assert(process.platform === "darwin", "Signed macOS desktop release builds must run on macOS.");
if (isCi) {
assert(isTagBuild, "Signed desktop release candidate builds in CI must run from a release tag.");
@@ -64,6 +93,18 @@ if (env.REQUIRE_DESKTOP_SIGNING === "true") {
}
}
if (requiresWindowsSigning) {
assert(process.platform === "win32", "Signed Windows desktop release builds must run on Windows.");
if (isCi) {
assert(isTagBuild, "Signed Windows desktop release candidate builds in CI must run from a release tag.");
}
requireEnv("TAURI_SIGNING_PRIVATE_KEY");
requireEnv("TAURI_SIGNING_PRIVATE_KEY_PASSWORD");
requireEnv("WINDOWS_CERTIFICATE");
requireEnv("WINDOWS_CERTIFICATE_PASSWORD");
requireEnv("WINDOWS_TIMESTAMP_URL");
}
if (failures.length > 0) {
console.error(`Release build environment check failed:\n${failures.map((item) => ` - ${item}`).join("\n")}`);
process.exitCode = 1;