docs: align frontend release validation on master

This commit is contained in:
Codex
2026-05-20 11:42:43 +00:00
parent 8f4827c204
commit 4c94b27920
4 changed files with 36 additions and 9 deletions
+2 -2
View File
@@ -1657,8 +1657,8 @@ export function ciHelp(): Record<string, unknown> {
catalog: catalog.artifacts.map(catalogArtifactDescriptor),
boundary: "artifact producer only; no prod deploy and no production namespace mutation",
frontendNext: [
"bun scripts/cli.ts deploy apply --env dev --service frontend",
"bun scripts/cli.ts deploy apply --env prod --service frontend",
"bun scripts/cli.ts deploy apply --env dev --service frontend --commit <full-sha>",
"bun scripts/cli.ts deploy apply --env prod --service frontend --commit <full-sha>",
],
},
runDevE2E: {
+24 -3
View File
@@ -210,11 +210,17 @@ export function deployHelp(action: string | undefined = undefined): Record<strin
apply: "Start an async target-side reconcile job unless --run-now is explicitly present.",
guard: "Run local deployment guards without mutating runtime resources.",
},
releaseV1Frontend: {
producer: "bun scripts/cli.ts ci publish-user-service --service frontend --commit <release-v1-full-sha> --wait-ms 1200000",
devConsumer: "bun scripts/cli.ts deploy apply --env dev --service frontend --commit <release-v1-full-sha>",
prodConsumer: "bun scripts/cli.ts deploy apply --env prod --service frontend --commit <release-v1-full-sha>",
boundary: "--commit selects an existing commit-pinned registry artifact for one reviewed artifact consumer; it does not read a dirty local manifest or make the server rebuild a release path.",
},
options: [
{ name: "--file <path>", default: defaultDeployFile, description: "Desired-state manifest path relative to the repo root. JSON and ESM JS manifests are supported, for example deploy.json or develop.js. Local D601 maintenance apply is limited to approved direct exceptions; Code Queue direct rollout is disabled." },
{ name: "--env <dev|prod>", description: "Read the named environment from origin/master:deploy.json. Dev apply supports backend-core target-side rollout plus reviewed artifact consumers for frontend, baidu-netdisk, decision-center, mdtodo, claudeqq, dev-only code-queue, project-manager, oa-event-flow, code-queue-mgr, todo-note, findjob, pipeline, and met-nonlinear. Prod apply uses reviewed D601 registry artifact consumers; code-queue has no prod target and gated/incomplete services return structured unsupported or dry-run-only output." },
{ name: "--service <id>", description: "Limit reconcile to one service from the manifest." },
{ name: "--commit <full-sha>", description: "Prod artifact rollback/apply override for a selected service; the image must already exist in D601 registry." },
{ name: "--commit <full-sha>", description: "Artifact consumer override for one selected --env dev|prod service; the commit-pinned image must already exist in the D601 registry. This is the supported release/v1 frontend validation and rollback shape without editing a local manifest." },
{ name: "--dry-run", description: "Prepare and validate without mutating the target service." },
{ name: "--force", description: "Redeploy even when the live commit appears up to date." },
{ name: "--timeout-ms <n>", default: defaultTimeoutMs, description: "Per-step timeout budget where supported." },
@@ -485,9 +491,9 @@ function parseOptions(args: string[]): DeployOptions {
if (environment !== null && args.includes("--file")) throw new Error("deploy --env reads deploy.json from the fixed Git ref and cannot be combined with --file");
const commitOverride = optionValue(args, ["--commit"]);
const serviceId = optionValue(args, ["--service", "--service-id"]) ?? null;
if (commitOverride !== undefined && environment !== "prod") throw new Error("deploy --commit is only supported for --env prod artifact rollback/apply");
if (commitOverride !== undefined && environment === null) throw new Error("deploy --commit is only supported for --env dev|prod artifact consumer apply");
if (commitOverride !== undefined && !isFullGitSha(commitOverride)) throw new Error("deploy --commit must be a full 40-character commit SHA");
if (commitOverride !== undefined && serviceId === null) throw new Error("deploy --commit requires --service so prod rollback/apply is unambiguous");
if (commitOverride !== undefined && serviceId === null) throw new Error("deploy --commit requires --service so artifact consumer apply is unambiguous");
return {
file: optionValue(args, ["--file"]) ?? defaultDeployFile,
environment,
@@ -2818,6 +2824,19 @@ function prodArtifactUnsupportedResult(services: DeployManifestService[]): Recor
};
}
function commitOverrideArtifactConsumerError(options: DeployOptions): string | null {
if (options.commitOverride === null) return null;
if (options.environment === "dev") {
if (options.serviceId !== null && devArtifactConsumerServiceIds.has(options.serviceId)) return null;
return `deploy --commit is supported for --env dev only on reviewed artifact consumers (${Array.from(devArtifactConsumerServiceIds).sort().join(", ")}); it must not switch dev target-side source builds such as backend-core away from deploy.json`;
}
if (options.environment === "prod") {
if (options.serviceId !== null && prodArtifactConsumerServiceIds.has(options.serviceId)) return null;
return `deploy --commit is supported for --env prod only on reviewed artifact consumers (${Array.from(prodArtifactConsumerServiceIds).sort().join(", ")})`;
}
return "deploy --commit is supported only for --env dev|prod artifact consumer apply";
}
function prodArtifactConsumerLocalManifestResult(services: DeployManifestService[]): Record<string, unknown> {
return {
ok: false,
@@ -3009,6 +3028,8 @@ export async function runDeployCommand(config: UniDeskConfig | null, args: strin
const action = actionRaw as DeployAction;
const options = parseOptions(args.slice(1));
if (options.environment !== null) {
const commitOverrideError = commitOverrideArtifactConsumerError(options);
if (commitOverrideError !== null) throw new Error(commitOverrideError);
const { manifest, source } = readEnvironmentDeployManifest(options.environment);
if (action === "check" || action === "plan") return environmentDryRunPlan(manifest, source, options, action);
if (options.environment === "prod") {
+6 -2
View File
@@ -14,7 +14,7 @@ export function rootHelp(): unknown {
{ command: "server status", description: "Show fixed ports, containers, service health, and public URLs." },
{ command: "server swap status|ensure [--path /swapfile] [--size 2GiB] [--dry-run]", description: "Inspect or idempotently create host swap for low-memory main-server operation." },
{ command: "server logs [--tail-bytes N]", description: "Return bounded tails from file logs and docker logs." },
{ command: "server rebuild <backend-core|frontend|dev-frontend-proxy|provider-gateway|todo-note|code-queue-mgr|project-manager|baidu-netdisk|oa-event-flow>", description: "Maintenance-only local Compose rebuild for reviewed main-server services; unsupported objects return structured errors instead of falling back to source builds." },
{ command: "server rebuild <backend-core|frontend|dev-frontend-proxy|provider-gateway|todo-note|code-queue-mgr|project-manager|baidu-netdisk|oa-event-flow>", description: "Maintenance-only local Compose rebuild for reviewed main-server services; frontend standard release must use CI artifact plus deploy apply dev/prod artifact consumers." },
{ command: "provider attach <providerId> [--master-server URL] [--up] [--force]", description: "Generate the minimal external provider-gateway env/compose bundle; only master server URL and provider id are required." },
{ command: "ssh <providerId> [ssh-like args...]", description: "Open a Host SSH / WSL SSH maintenance session through the provider-gateway bridge with built-in remote helper tools in PATH." },
{ command: "ssh <providerId> apply-patch [tool args...] < patch.diff", description: "Invoke the injected remote apply_patch helper directly over SSH passthrough and stream the patch from local stdin." },
@@ -40,7 +40,7 @@ export function rootHelp(): unknown {
{ command: "decision list [--type ...] [--status ...] [--level|--priority ...] [--source text] [--issue id] [--linked-goal-id id] [--limit N]", description: "List Decision Center records through the user-service proxy." },
{ command: "decision requirement list|create|show|update|upsert [id] [--title text] [--body-file path] [--type external_goal|internal_goal|goal|decision|blocker|debt|experiment] [--source text] [--issue id]", description: "Manage productized requirement records over the PostgreSQL records model, excluding meeting records." },
{ command: "decision show <id>", description: "Show one Decision Center record." },
{ command: "deploy check|plan|apply [--file deploy.json|--env dev|prod] [--service id] [--commit full-sha] [--dry-run] [--force]", description: "Reconcile services from a repo+commit manifest; --env reads origin/master:deploy.json environments and applies supported dev target-side rollouts or reviewed D601 registry artifact consumers. code-queue artifact consumption is dev-only." },
{ command: "deploy check|plan|apply [--file deploy.json|--env dev|prod] [--service id] [--commit full-sha] [--dry-run] [--force]", description: "Reconcile services from origin/master:deploy.json environments; --commit overrides one reviewed artifact consumer such as frontend for release/v1 validation or rollback. code-queue artifact consumption is dev-only." },
{ command: "dev-env validate|prewarm-images", description: "Validate D601 unidesk-dev guardrails or prewarm dev foundation images into native k3s containerd through a bounded async job." },
{ command: "artifact-registry plan|render|status|health|install|deploy-backend-core|deploy-service", description: "Manage the D601 host-managed CNCF Distribution registry and run pull-only artifact CD for supported services, including D601 direct, k3s-managed, and code-queue dev-only consumers." },
{ command: "gh auth|issue|pr", description: "Run safe GitHub issue and PR list/view/create/comment operations through REST with body-file support, token diagnostics, escape scanning, and merge blocked." },
@@ -96,6 +96,10 @@ export function serverHelp(action: string | undefined = undefined): unknown {
masterServer: "do not use server rebuild backend-core for Rust iteration; it would build locally",
d601: "use deploy apply --env dev --service backend-core and CI for Rust build/check",
},
maintenanceOnly: {
frontend: "server rebuild frontend is not standard release evidence; publish 127.0.0.1:5000/unidesk/frontend:<commit> with CI, then consume it with deploy apply --env dev/prod --service frontend --commit <full-sha>",
userServices: "server rebuild for main-server user services is reserved for local maintenance, bootstrap or recovery and must not replace commit-pinned artifact CD",
},
nonRebuildableBoundary: {
upstreamImages: ["filebrowser", "filebrowser-d601"],
infrastructure: ["database", "k3sctl-adapter"],