Files
pikasTech-unidesk/scripts/src/artifact-registry/entry.ts
T
Lyon edfddd2445 fix: YAML-first 治理 CI/CD target (#919)
* docs: specify cicd yaml target governance

* fix: resolve cicd targets from yaml

---------

Co-authored-by: Codex <codex@noreply.local>
2026-06-26 01:14:38 +08:00

192 lines
13 KiB
TypeScript

// SPEC: PJ2026-01060307 控制面模块化 draft-2026-06-25-p0. entry module for scripts/src/artifact-registry.ts.
// SPEC: PJ2026-01060308 cicd-yaml-targets draft-2026-06-25-cicd-yaml-targets.
// Moved mechanically from scripts/src/artifact-registry.ts:3448-3700 for #903.
import { createHash } from "node:crypto";
import { existsSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { runCommand, type CommandResult } from "../command";
import { readConfig, type UniDeskConfig, repoRoot, rootPath } from "../config";
import { startJob } from "../jobs";
import {
compareDeployJsonExecutorMirrors,
deployJsonCommitImage,
deployJsonDriftResult,
deployJsonSourceOfTruth,
hasDeployJsonExecutorContract,
k3sManifestExecutorMirror,
parseDeployJsonServiceContractBase64,
readDeployJsonServiceContractFromFile,
type DeployJsonExecutorMirror,
type DeployJsonServiceContract,
} from "../deploy-json-contract";
import { d601K3sGuardShellLines } from "../d601-k3s-guard";
import { composeRuntimeEnvValue } from "../runtime-env";
import type { ArtifactRegistryAction, ArtifactRegistryCommandRuntime, ArtifactRegistryOptions } from "./types";
import { renderBundle } from "./bundle";
import { deployBackendCoreJob, deployBackendCoreNow, deployComposeArtifactNow, deployD601ComposeArtifactNow, dryRunArtifactConsumerPlan, legacyDeployBackendCoreResult } from "./compose-deploy";
import { artifactConsumerLiveBlock, artifactConsumerSpec, artifactConsumerTarget, supportedArtifactConsumers, unsupportedEnvironment, unsupportedService } from "./consumer";
import { install, installDryRun } from "./install";
import { deployD601K3sArtifactNow, rollbackInfo } from "./k3s-deploy";
import { isHelpArg, parseArtifactRegistryOptions } from "./options";
import { runReadonlyStatusWithRemoteFallback } from "./readonly";
import { plan } from "./status";
import { defaultOptions, legacyDeployBackendCoreDisabled, supportedArtifactConsumerServices } from "./types";
export async function deployServiceNow(options: ArtifactRegistryOptions): Promise<Record<string, unknown>> {
if (options.serviceId === null) throw new Error("artifact-registry deploy-service requires --service <id>");
if (options.commit === null) throw new Error("artifact-registry deploy-service requires --commit <full-sha>");
const spec = artifactConsumerSpec(options.serviceId, options.environment);
if (spec === null) return unsupportedService(options.serviceId, options);
const target = artifactConsumerTarget(spec, options.environment);
if (target === null) return unsupportedEnvironment(spec, options);
if (options.dryRun) return dryRunArtifactConsumerPlan(options, spec, target, options.commit);
const liveBlock = artifactConsumerLiveBlock(spec, options);
if (liveBlock !== null) return liveBlock;
if (spec.kind === "compose") return deployComposeArtifactNow(options, spec, target);
if (spec.kind === "d601-compose") return deployD601ComposeArtifactNow(options, spec, target);
return deployD601K3sArtifactNow(options, spec, target);
}
export function deployServiceJob(args: string[], options: ArtifactRegistryOptions): Record<string, unknown> {
if (options.serviceId === null) throw new Error("artifact-registry deploy-service requires --service <id>");
if (options.commit === null) throw new Error("artifact-registry deploy-service requires --commit <full-sha>");
const spec = artifactConsumerSpec(options.serviceId, options.environment);
if (spec === null) return unsupportedService(options.serviceId, options);
const target = artifactConsumerTarget(spec, options.environment);
if (target === null) return unsupportedEnvironment(spec, options);
if (options.dryRun) return dryRunArtifactConsumerPlan(options, spec, target, options.commit);
const liveBlock = artifactConsumerLiveBlock(spec, options);
if (liveBlock !== null) return liveBlock;
const runArgs = args.includes("--run-now") ? args : [...args, "--run-now"];
const command = [process.execPath, rootPath("scripts", "cli.ts"), "artifact-registry", ...runArgs];
const job = startJob("artifact_registry_service_cd", command, `Pull and deploy ${options.environment ?? "prod"} ${options.serviceId} artifact ${options.commit} from D601 registry`);
return {
ok: true,
mode: "async-job",
serviceId: options.serviceId,
environment: options.environment ?? "prod",
job,
statusCommand: `bun scripts/cli.ts job status ${job.id}`,
tailCommand: `bun scripts/cli.ts job status ${job.id} --tail-bytes 30000`,
note: "User-service CD continues in the background: D601 registry health, commit-pinned artifact check, pull/import, rollout, image-label and live health commit verification.",
rollback: rollbackInfo(spec, target, options.environment ?? "prod", options.commit),
};
}
export function serviceIdFromDeployBackendCoreArgs(action: ArtifactRegistryAction, options: ArtifactRegistryOptions): string | null {
return action === "deploy-backend-core" ? "backend-core" : options.serviceId;
}
export function localHelp(): Record<string, unknown> {
return {
ok: true,
command: "artifact-registry plan|render|status|health|install|deploy-backend-core|deploy-service",
output: "json",
usage: [
"bun scripts/cli.ts artifact-registry plan [--target D601]",
"bun scripts/cli.ts artifact-registry render [--target D601]",
"bun scripts/cli.ts artifact-registry status [--target D601]",
"bun scripts/cli.ts artifact-registry health [--target D601]",
"bun scripts/cli.ts artifact-registry install [--target D601]",
"bun scripts/cli.ts artifact-registry deploy-service --service baidu-netdisk --commit <full-sha> [--dry-run] [--run-now] [--target D601]",
"bun scripts/cli.ts artifact-registry deploy-service --service frontend --env prod --commit <full-sha> [--dry-run] [--run-now] [--target D601]",
"bun scripts/cli.ts artifact-registry deploy-service --service frontend --env dev --commit <full-sha> [--dry-run] [--run-now] [--target D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service decision-center --commit <full-sha> [--dry-run] [--run-now] [--target D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service decision-center --commit <full-sha> [--dry-run] [--run-now] [--target D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service project-manager --commit <full-sha> [--dry-run] [--run-now] [--target D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service oa-event-flow --commit <full-sha> [--dry-run] [--run-now] [--target D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service code-queue-mgr --commit <full-sha> --dry-run [--target D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service todo-note --commit <full-sha> [--dry-run] [--run-now] [--target D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service todo-note --commit <full-sha> [--dry-run] [--run-now] [--target D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service findjob --commit <full-sha> [--dry-run] [--run-now] [--target D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service findjob --commit <full-sha> [--dry-run] [--run-now] [--target D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service pipeline --commit <full-sha> [--dry-run] [--run-now] [--target D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service pipeline --commit <full-sha> [--dry-run] [--run-now] [--target D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service met-nonlinear --commit <full-sha> --dry-run [--target D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service met-nonlinear --commit <full-sha> --dry-run [--target D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service k3sctl-adapter --commit <full-sha> --dry-run [--target D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service mdtodo --commit <full-sha> [--dry-run] [--run-now] [--target D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service mdtodo --commit <full-sha> [--dry-run] [--run-now] [--target D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service claudeqq --commit <full-sha> [--dry-run] [--run-now] [--target D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service claudeqq --commit <full-sha> [--dry-run] [--run-now] [--target D601]",
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service code-queue --commit <full-sha> --dry-run [--target D601]",
],
firstStage: "install now writes the rendered systemd/Compose/config files and starts the registry",
artifactConsumers: {
supportedServices: supportedArtifactConsumerServices,
supportedConsumers: supportedArtifactConsumers(),
unsupportedPolicy: "return structured unsupported; never fall back to legacy maintenance-channel source builds",
prodCommands: [
"bun scripts/cli.ts deploy apply --env prod --service backend-core",
"bun scripts/cli.ts deploy apply --env prod --service baidu-netdisk",
"bun scripts/cli.ts deploy apply --env prod --service frontend",
"bun scripts/cli.ts deploy apply --env prod --service decision-center",
"bun scripts/cli.ts deploy apply --env prod --service project-manager",
"bun scripts/cli.ts deploy apply --env prod --service oa-event-flow",
"bun scripts/cli.ts deploy apply --env prod --service code-queue-mgr --dry-run",
"bun scripts/cli.ts deploy apply --env prod --service todo-note",
"bun scripts/cli.ts deploy apply --env prod --service findjob",
"bun scripts/cli.ts deploy apply --env prod --service pipeline",
"bun scripts/cli.ts deploy apply --env prod --service met-nonlinear --dry-run",
"bun scripts/cli.ts deploy apply --env prod --service k3sctl-adapter --dry-run",
"bun scripts/cli.ts deploy apply --env prod --service mdtodo",
"bun scripts/cli.ts deploy apply --env prod --service claudeqq",
],
devCommands: [
"bun scripts/cli.ts deploy apply --env dev --service frontend",
"bun scripts/cli.ts deploy apply --env dev --service decision-center",
"bun scripts/cli.ts deploy apply --env dev --service project-manager --dry-run",
"bun scripts/cli.ts deploy apply --env dev --service oa-event-flow --dry-run",
"bun scripts/cli.ts deploy apply --env dev --service code-queue-mgr --dry-run",
"bun scripts/cli.ts deploy apply --env dev --service todo-note",
"bun scripts/cli.ts deploy apply --env dev --service findjob --dry-run",
"bun scripts/cli.ts deploy apply --env dev --service pipeline --dry-run",
"bun scripts/cli.ts deploy apply --env dev --service met-nonlinear --dry-run",
"bun scripts/cli.ts deploy apply --env dev --service mdtodo",
"bun scripts/cli.ts deploy apply --env dev --service claudeqq",
"bun scripts/cli.ts deploy apply --env dev --service code-queue --dry-run",
],
devOnlyConsumers: ["code-queue"],
rollbackShape: "rerun the same artifact consumer with a previous commit-pinned image",
},
legacyEntrypoints: {
"deploy-backend-core": {
deprecated: true,
enabled: !legacyDeployBackendCoreDisabled,
replacement: "bun scripts/cli.ts deploy apply --env prod --service backend-core --commit <full-sha>",
},
},
defaults: defaultOptions,
};
}
export async function runArtifactRegistryCommand(args: string[], runtime: ArtifactRegistryCommandRuntime = {}): Promise<unknown> {
const action = args[0];
if (isHelpArg(action)) return localHelp();
if (action !== "plan" && action !== "render" && action !== "status" && action !== "health" && action !== "install" && action !== "deploy-backend-core" && action !== "deploy-service") {
throw new Error("artifact-registry usage: plan|render|status|health|install|deploy-backend-core|deploy-service");
}
const typedAction = action as ArtifactRegistryAction;
const options = parseArtifactRegistryOptions(args.slice(1));
if (action === "plan") return plan(options);
if (action === "render") return { ok: true, providerId: options.providerId, render: renderBundle(options) };
if (action === "status") return runReadonlyStatusWithRemoteFallback(options, false, runtime);
if (action === "health") return runReadonlyStatusWithRemoteFallback(options, true, runtime);
if (action === "install") {
return options.dryRun ? installDryRun(options) : install(options);
}
if (action === "deploy-backend-core") {
if (options.commit === null) throw new Error("artifact-registry deploy-backend-core requires --commit <full-sha>");
if (legacyDeployBackendCoreDisabled) return legacyDeployBackendCoreResult(options);
return options.runNow ? await deployBackendCoreNow(options) : deployBackendCoreJob(args, options);
}
if (action === "deploy-service") {
const serviceId = serviceIdFromDeployBackendCoreArgs(typedAction, options);
return options.runNow || options.dryRun ? await deployServiceNow({ ...options, serviceId }) : deployServiceJob(args, { ...options, serviceId });
}
throw new Error("unreachable artifact-registry action");
}