refactor: split control-plane cli modules
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
// SPEC: PJ2026-01060307 控制面模块化 draft-2026-06-25-p0. entry module for scripts/src/ci.ts.
|
||||
|
||||
// Moved mechanically from scripts/src/ci.ts:3410-3600 for #903.
|
||||
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join, posix as posixPath } from "node:path";
|
||||
import { blockedCatalogArtifactIds, catalogSummary, findCiCatalogArtifact, loadCiCatalog, supportedSourceBuildArtifactIds, type CiCatalogArtifact, type CiSourceBuildCatalogArtifact, type CiUpstreamImageCatalogArtifact } from "../ci-catalog";
|
||||
import { runCommand } from "../command";
|
||||
import { type UniDeskConfig, repoRoot, rootPath } from "../config";
|
||||
import { ensureGithubSshIdentityForProvider, gitSshHttpConnectProxySource } from "../deploy-ssh-identity";
|
||||
import { jobWithTail, listJobs, readJob, startJob } from "../jobs";
|
||||
import { coreInternalFetch } from "../microservices";
|
||||
import {
|
||||
artifactRegistryReadonlyResultFromCommand,
|
||||
buildArtifactRegistryReadonlyProbe,
|
||||
parseArtifactRegistryOptions,
|
||||
type ArtifactRegistryReadonlyProbe,
|
||||
} from "../artifact-registry";
|
||||
import { d601K3sGuardShellLines, d601NativeKubeconfig } from "../d601-k3s-guard";
|
||||
import { runSshCommandCapture } from "../ssh";
|
||||
|
||||
import { cleanupFailedPods, cleanupRuns, status } from "./cleanup";
|
||||
import { makeRunId, resolveDeployDevManifest, runDevE2E } from "./dev-e2e";
|
||||
import { ciHelp, requireRunId } from "./help";
|
||||
import { install, installAsync, installStatus } from "./install";
|
||||
import { logs } from "./logs";
|
||||
import { blockedArtifactResult, blockedReason, boolFlag, ciCleanupFailedPodsOptions, ciCleanupRunsOptions, ciLogsOptions, isHelpArg, numberOption, publishTransportOption, requireDesiredRef, requireFullCommit, requireRepoRelativePath, requireRevision, requireServiceId, resolveCatalogArtifact, stringOption, userServicePublishBoundaryBlock } from "./options";
|
||||
import { backendCoreArtifactSourceHostPath, userServiceArtifactSourceHostPath } from "./pipelinerun";
|
||||
import { publishBackendCoreArtifact, publishUserServiceArtifact, run } from "./publish";
|
||||
import { ciTarget, d601ProviderId, providerIdOption } from "./types";
|
||||
|
||||
export async function runCiCommand(config: UniDeskConfig, args: string[]): Promise<Record<string, unknown>> {
|
||||
const [action = "status", nameArg] = args;
|
||||
if (isHelpArg(action) || args.slice(1).some(isHelpArg)) return ciHelp();
|
||||
if (action === "install") {
|
||||
const options = {
|
||||
target: ciTarget(providerIdOption(args)),
|
||||
skipPrewarm: boolFlag(args, "--skip-prewarm"),
|
||||
skipTektonInstall: boolFlag(args, "--skip-tekton-install"),
|
||||
wait: boolFlag(args, "--wait"),
|
||||
};
|
||||
return options.wait ? install(config, options) : installAsync(options);
|
||||
}
|
||||
if (action === "install-status") return installStatus(nameArg ?? "latest");
|
||||
if (action === "status") return status(ciTarget(providerIdOption(args)));
|
||||
if (action === "run") {
|
||||
const target = ciTarget(providerIdOption(args));
|
||||
const repoUrl = stringOption(args, "--repo") ?? stringOption(args, "--repo-url") ?? "https://github.com/pikasTech/unidesk";
|
||||
const revision = requireRevision(stringOption(args, "--revision") ?? stringOption(args, "--commit"));
|
||||
const waitMs = numberOption(args, "--wait-ms", 0);
|
||||
return run({ repoUrl, revision, waitMs, target });
|
||||
}
|
||||
if (action === "publish-backend-core") {
|
||||
if (stringOption(args, "--repo") !== null || stringOption(args, "--repo-url") !== null) {
|
||||
throw new Error("ci publish-backend-core reads source repo from CI.json; edit CI.json instead of using --repo");
|
||||
}
|
||||
const commit = requireFullCommit(stringOption(args, "--commit") ?? stringOption(args, "--revision"));
|
||||
const waitMs = numberOption(args, "--wait-ms", 0);
|
||||
const dryRun = boolFlag(args, "--dry-run");
|
||||
const artifact = resolveCatalogArtifact("backend-core");
|
||||
if (artifact.kind !== "source-build") throw new Error("backend-core must be modeled as a source-build artifact in CI.json");
|
||||
if (artifact.status === "blocked") return blockedArtifactResult(artifact, commit, blockedReason(artifact));
|
||||
return publishBackendCoreArtifact(config, {
|
||||
repoUrl: artifact.source.repo,
|
||||
commit,
|
||||
waitMs,
|
||||
sourceHostPath: backendCoreArtifactSourceHostPath(commit),
|
||||
dockerfile: artifact.source.dockerfile,
|
||||
imageRepository: artifact.image.repository,
|
||||
dryRun,
|
||||
});
|
||||
}
|
||||
if (action === "publish-user-service") {
|
||||
const serviceId = requireServiceId(stringOption(args, "--service") ?? stringOption(args, "--service-id"));
|
||||
const commit = requireFullCommit(stringOption(args, "--commit") ?? stringOption(args, "--revision"));
|
||||
const waitMs = numberOption(args, "--wait-ms", 0);
|
||||
const dryRun = boolFlag(args, "--dry-run");
|
||||
const transport = publishTransportOption(stringOption(args, "--transport"));
|
||||
if (stringOption(args, "--repo") !== null || stringOption(args, "--repo-url") !== null) {
|
||||
throw new Error("ci publish-user-service reads source repo from CI.json; edit CI.json instead of using --repo");
|
||||
}
|
||||
const artifact = resolveCatalogArtifact(serviceId);
|
||||
if (artifact.kind === "source-build" && artifact.serviceId === "backend-core") {
|
||||
throw new Error("backend-core uses ci publish-backend-core; publish-user-service is for registered user services");
|
||||
}
|
||||
if (artifact.kind === "upstream-image") {
|
||||
return blockedArtifactResult(artifact, commit, artifact.blockedReason);
|
||||
}
|
||||
if (artifact.status === "blocked") {
|
||||
return blockedArtifactResult(artifact, commit, blockedReason(artifact));
|
||||
}
|
||||
const repoUrl = artifact.source.repo;
|
||||
const dockerfile = requireRepoRelativePath(artifact.source.dockerfile, `CI.json.artifacts.${serviceId}.source.dockerfile`);
|
||||
const boundaryBlock = userServicePublishBoundaryBlock(config, serviceId, commit, artifact);
|
||||
if (boundaryBlock !== null) return boundaryBlock;
|
||||
return publishUserServiceArtifact(config, {
|
||||
repoUrl,
|
||||
commit,
|
||||
waitMs,
|
||||
serviceId,
|
||||
dockerfile,
|
||||
imageRepository: artifact.image.repository,
|
||||
sourceHostPath: userServiceArtifactSourceHostPath(serviceId, commit),
|
||||
dryRun,
|
||||
transport,
|
||||
});
|
||||
}
|
||||
if (action === "run-dev-e2e") {
|
||||
const repoUrl = stringOption(args, "--repo") ?? stringOption(args, "--repo-url") ?? "https://github.com/pikasTech/unidesk";
|
||||
const desiredRef = requireDesiredRef(stringOption(args, "--desired-ref") ?? stringOption(args, "--deploy-branch"));
|
||||
const manifest = resolveDeployDevManifest(desiredRef);
|
||||
const waitMs = numberOption(args, "--wait-ms", 0);
|
||||
const runId = requireRunId(stringOption(args, "--run-id") ?? makeRunId(manifest.deployCommit));
|
||||
return runDevE2E({
|
||||
repoUrl,
|
||||
desiredRef,
|
||||
deployCommit: manifest.deployCommit,
|
||||
environment: manifest.environment,
|
||||
scriptRepo: manifest.ci.repo,
|
||||
scriptPath: manifest.ci.scriptPath,
|
||||
scriptTimeoutMs: manifest.ci.timeoutMs,
|
||||
services: manifest.services,
|
||||
runId,
|
||||
keepNamespace: boolFlag(args, "--keep-namespace"),
|
||||
waitMs,
|
||||
});
|
||||
}
|
||||
if (action === "logs") return logs(config, nameArg ?? "", ciTarget(providerIdOption(args)), ciLogsOptions(args));
|
||||
if (action === "cleanup-runs") return cleanupRuns(config, ciCleanupRunsOptions(args));
|
||||
if (action === "cleanup-failed-pods") return cleanupFailedPods(config, ciCleanupFailedPodsOptions(args));
|
||||
throw new Error("ci command must be one of: install, status, run, publish-backend-core, publish-user-service, run-dev-e2e, logs, cleanup-runs, cleanup-failed-pods");
|
||||
}
|
||||
|
||||
export function startCiInstallJob(providerId = d601ProviderId): Record<string, unknown> {
|
||||
return installAsync({
|
||||
target: ciTarget(providerId),
|
||||
skipPrewarm: false,
|
||||
skipTektonInstall: false,
|
||||
wait: false,
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user