feat: add baidu netdisk artifact delivery

This commit is contained in:
Codex
2026-05-19 15:22:56 +00:00
parent 11d7b217d9
commit c8561d392b
17 changed files with 302 additions and 103 deletions
+67 -13
View File
@@ -135,7 +135,8 @@ const nativeK3sCtrAddress = "/run/k3s/containerd/containerd.sock";
const unideskRepoUrl = "https://github.com/pikasTech/unidesk";
const d601MaintenanceDeployAllowedServiceIds = new Set<string>(["backend-core", "frontend", "k3sctl-adapter", "code-queue"]);
const devApplySupportedServiceIds = new Set<string>(["backend-core", "frontend"]);
const prodArtifactConsumerServiceIds = new Set<string>(["backend-core", "decision-center"]);
const devArtifactConsumerServiceIds = new Set<string>(["baidu-netdisk"]);
const prodArtifactConsumerServiceIds = new Set<string>(["backend-core", "baidu-netdisk", "decision-center"]);
const deployEnvironmentTargets: Record<DeployEnvironment, DeployEnvironmentTarget> = {
dev: {
environment: "dev",
@@ -198,7 +199,7 @@ export function deployHelp(action: string | undefined = undefined): Record<strin
},
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 manifest apply allows k3sctl-adapter and explicit production code-queue controlled rollout on D601." },
{ name: "--env <dev|prod>", description: "Read the named environment from origin/master:deploy.json. Dev apply is enabled only for backend-core and frontend in D601 unidesk-dev; prod apply uses the D601 registry artifact consumer for backend-core and decision-center." },
{ name: "--env <dev|prod>", description: "Read the named environment from origin/master:deploy.json. Dev apply supports backend-core/frontend target-side rollout plus baidu-netdisk artifact validation; prod apply uses the D601 registry artifact consumer for backend-core, baidu-netdisk, and decision-center." },
{ 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: "--dry-run", description: "Prepare and validate without mutating the target service." },
@@ -2476,12 +2477,17 @@ function environmentDryRunPlan(
? prodArtifactConsumerServiceIds.has(service.id)
? "d601-registry-artifact-consumer"
: "unsupported"
: "d601-dev-target-side-build",
unsupported: environment === "prod" && !prodArtifactConsumerServiceIds.has(service.id)
: devArtifactConsumerServiceIds.has(service.id)
? "d601-registry-artifact-consumer-dev-validation"
: "d601-dev-target-side-build",
unsupported: (environment === "prod" && !prodArtifactConsumerServiceIds.has(service.id))
|| (environment === "dev" && !devApplySupportedServiceIds.has(service.id) && !devArtifactConsumerServiceIds.has(service.id))
? {
ok: false,
supported: false,
reason: "No standardized prod D601 registry artifact consumer is implemented for this service; legacy maintenance-channel deployment is not allowed.",
reason: environment === "prod"
? "No standardized prod D601 registry artifact consumer is implemented for this service; legacy maintenance-channel deployment is not allowed."
: "No standardized dev deployment or artifact validation path is implemented for this service.",
}
: undefined,
})),
@@ -2491,7 +2497,7 @@ function environmentDryRunPlan(
function unsupportedDevApplyServices(manifest: DeployManifest, serviceId: string | null): string[] {
if (manifest.environment !== "dev") return [];
const services = serviceId === null ? manifest.services : manifest.services.filter((service) => service.id === serviceId);
return services.map((service) => service.id).filter((id) => !devApplySupportedServiceIds.has(id));
return services.map((service) => service.id).filter((id) => !devApplySupportedServiceIds.has(id) && !devArtifactConsumerServiceIds.has(id));
}
function blockedD601MaintenanceDeployServices(config: UniDeskConfig, manifest: DeployManifest, serviceId: string | null): string[] {
@@ -2505,6 +2511,16 @@ function d601MaintenanceDeployBlockMessage(blocked: string[]): string {
return `D601 target-side deployment is enabled only for k3sctl-adapter and dev backend-core/frontend; blocked services: ${blocked.join(", ")}. Use ci run-dev-e2e for dev smoke verification.`;
}
function selectedDevArtifactServices(manifest: DeployManifest, serviceId: string | null): DeployManifestService[] {
if (manifest.environment !== "dev") return [];
return selectedEnvironmentServices(manifest, serviceId).filter((service) => devArtifactConsumerServiceIds.has(service.id));
}
function selectedDevTargetServices(manifest: DeployManifest, serviceId: string | null): DeployManifestService[] {
if (manifest.environment !== "dev") return [];
return selectedEnvironmentServices(manifest, serviceId).filter((service) => devApplySupportedServiceIds.has(service.id));
}
function selectedEnvironmentServices(manifest: DeployManifest, serviceId: string | null): DeployManifestService[] {
const services = serviceId === null ? manifest.services : manifest.services.filter((service) => service.id === serviceId);
if (serviceId !== null && services.length === 0) throw new Error(`deploy manifest does not contain service: ${serviceId}`);
@@ -2532,10 +2548,12 @@ function prodArtifactUnsupportedResult(services: DeployManifestService[]): Recor
};
}
async function runProdArtifactApplyNow(manifest: DeployManifest, options: DeployOptions): Promise<Record<string, unknown>> {
const selected = selectedEnvironmentServices(manifest, options.serviceId);
const unsupported = selected.filter((service) => !prodArtifactConsumerServiceIds.has(service.id));
if (unsupported.length > 0) return prodArtifactUnsupportedResult(unsupported);
async function runArtifactConsumerApplyNow(
manifest: DeployManifest,
options: DeployOptions,
environment: "dev" | "prod",
selected: DeployManifestService[],
): Promise<Record<string, unknown>> {
const startedAt = nowIso();
const results = [];
for (const service of selected) {
@@ -2545,11 +2563,12 @@ async function runProdArtifactApplyNow(manifest: DeployManifest, options: Deploy
"--service", service.id,
"--commit", commit,
"--source-repo", service.repo,
"--deploy-ref", `deploy.json#environments.${environment}.services.${service.id}`,
"--timeout-ms", String(options.timeoutMs),
"--run-now",
...(options.dryRun ? ["--dry-run"] : []),
];
progressLine("prod-artifact-cd", options.dryRun ? "dry-run" : "reconcile", { serviceId: service.id, commit });
progressLine(`${environment}-artifact-cd`, options.dryRun ? "dry-run" : "reconcile", { serviceId: service.id, commit });
results.push(await runArtifactRegistryCommand(artifactArgs));
const latest = results.at(-1) as Record<string, unknown>;
if (latest.ok !== true) break;
@@ -2557,7 +2576,7 @@ async function runProdArtifactApplyNow(manifest: DeployManifest, options: Deploy
return {
ok: results.every((result) => asRecord(result)?.ok === true),
action: "apply",
environment: "prod",
environment,
executor: "d601-registry-artifact-consumer",
dryRun: options.dryRun,
startedAt,
@@ -2566,6 +2585,13 @@ async function runProdArtifactApplyNow(manifest: DeployManifest, options: Deploy
};
}
async function runProdArtifactApplyNow(manifest: DeployManifest, options: DeployOptions): Promise<Record<string, unknown>> {
const selected = selectedEnvironmentServices(manifest, options.serviceId);
const unsupported = selected.filter((service) => !prodArtifactConsumerServiceIds.has(service.id));
if (unsupported.length > 0) return prodArtifactUnsupportedResult(unsupported);
return runArtifactConsumerApplyNow(manifest, options, "prod", selected);
}
function prodArtifactApplyJob(args: string[], options: DeployOptions): Record<string, unknown> {
if (!options.runNow && options.dryRun) {
throw new Error("deploy apply --env prod --dry-run should run in the foreground so the plan is visible immediately");
@@ -2585,6 +2611,25 @@ function prodArtifactApplyJob(args: string[], options: DeployOptions): Record<st
};
}
function devArtifactApplyJob(args: string[], options: DeployOptions): Record<string, unknown> {
if (!options.runNow && options.dryRun) {
throw new Error("deploy apply --env dev --dry-run should run in the foreground so the plan is visible immediately");
}
const runArgs = args.includes("--run-now") ? args : [...args, "--run-now"];
const command = [process.execPath, rootPath("scripts", "cli.ts"), "deploy", ...runArgs];
const source = `${deployEnvironmentTargets.dev.gitRef}:deploy.json#environments.dev`;
const job = startJob("deploy_dev_artifact_apply", command, `Validate dev artifact consumer from ${source}${options.serviceId === null ? "" : ` service=${options.serviceId}`}`);
return {
ok: true,
mode: "async-job",
executor: "d601-registry-artifact-consumer-dev-validation",
job,
statusCommand: `bun scripts/cli.ts job status ${job.id}`,
tailCommand: `bun scripts/cli.ts job status ${job.id} --tail-bytes 30000`,
note: "Dev artifact validation continues in the background: D601 registry commit-pinned image check, pull-only Compose recreate, image-label and live health commit verification.",
};
}
async function runApplyNow(config: UniDeskConfig, manifest: DeployManifest, options: DeployOptions): Promise<Record<string, unknown>> {
const selected = selectServices(config, manifest, options.serviceId);
const startedAt = nowIso();
@@ -2639,7 +2684,16 @@ export async function runDeployCommand(config: UniDeskConfig | null, args: strin
}
const unsupported = unsupportedDevApplyServices(manifest, options.serviceId);
if (unsupported.length > 0) {
throw new Error(`deploy apply --env dev currently supports only backend-core and frontend; unsupported selected services: ${unsupported.join(", ")}. Use ci run-dev-e2e for smoke verification.`);
throw new Error(`deploy apply --env dev currently supports only backend-core/frontend target-side rollout and baidu-netdisk artifact validation; unsupported selected services: ${unsupported.join(", ")}. Use ci run-dev-e2e for smoke verification.`);
}
const devArtifactServices = selectedDevArtifactServices(manifest, options.serviceId);
const devTargetServices = selectedDevTargetServices(manifest, options.serviceId);
if (devArtifactServices.length > 0 && devTargetServices.length > 0) {
throw new Error("deploy apply --env dev cannot mix artifact validation services with target-side rollout services in one invocation; pass --service");
}
if (devArtifactServices.length > 0) {
if (options.dryRun || options.runNow) return await runArtifactConsumerApplyNow(manifest, options, "dev", devArtifactServices);
return devArtifactApplyJob(args, options);
}
if (config === null) throw new Error("deploy apply --env dev requires config.json");
if (!options.dryRun) {