refactor: split control-plane cli modules
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
// SPEC: PJ2026-01060307 控制面模块化 draft-2026-06-25-p0. help module for scripts/src/ci.ts.
|
||||
|
||||
// Moved mechanically from scripts/src/ci.ts:3273-3409 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 { g14CiPipelineManifest, tektonPipelineReleaseUrl, tektonPipelineVersion, tektonTriggersInterceptorsUrl, tektonTriggersReleaseUrl, tektonTriggersVersion } from "./types";
|
||||
|
||||
export function catalogArtifactDescriptor(artifact: CiCatalogArtifact): Record<string, unknown> {
|
||||
if (artifact.kind === "source-build") {
|
||||
return {
|
||||
serviceId: artifact.serviceId,
|
||||
kind: artifact.kind,
|
||||
status: artifact.status,
|
||||
producer: artifact.producer,
|
||||
source: artifact.source,
|
||||
image: artifact.image,
|
||||
...(artifact.notes === undefined ? {} : { notes: artifact.notes }),
|
||||
...(artifact.blockedReason === undefined ? {} : { blockedReason: artifact.blockedReason }),
|
||||
};
|
||||
}
|
||||
return {
|
||||
serviceId: artifact.serviceId,
|
||||
kind: artifact.kind,
|
||||
status: artifact.status,
|
||||
producer: artifact.producer,
|
||||
upstream: artifact.upstream,
|
||||
blockedReason: artifact.blockedReason,
|
||||
...(artifact.notes === undefined ? {} : { notes: artifact.notes }),
|
||||
};
|
||||
}
|
||||
|
||||
export function ciHelp(): Record<string, unknown> {
|
||||
const catalog = loadCiCatalog();
|
||||
return {
|
||||
command: "ci install|status|run|publish-backend-core|publish-user-service|run-dev-e2e|logs|cleanup-runs|cleanup-failed-pods",
|
||||
description: "Manage native k3s Tekton CI on D601 or G14. CI may publish commit-pinned image artifacts, but it intentionally does not deploy CD.",
|
||||
examples: [
|
||||
"bun scripts/cli.ts ci install",
|
||||
"bun scripts/cli.ts ci install --skip-prewarm",
|
||||
"bun scripts/cli.ts ci install --skip-prewarm --skip-tekton-install",
|
||||
"bun scripts/cli.ts ci install-status latest",
|
||||
"bun scripts/cli.ts ci install --wait --skip-prewarm --skip-tekton-install",
|
||||
"bun scripts/cli.ts ci install --provider-id G14",
|
||||
"bun scripts/cli.ts ci run --revision <commit>",
|
||||
"bun scripts/cli.ts ci run --provider-id G14 --revision <commit>",
|
||||
"bun scripts/cli.ts ci publish-backend-core --commit <full-sha>",
|
||||
"bun scripts/cli.ts ci publish-user-service --service baidu-netdisk --commit <full-sha>",
|
||||
"bun scripts/cli.ts ci publish-user-service --service mdtodo --commit <full-sha>",
|
||||
"bun scripts/cli.ts ci publish-user-service --service claudeqq --commit <full-sha>",
|
||||
"bun scripts/cli.ts ci publish-user-service --service code-queue --commit <full-sha>",
|
||||
"bun scripts/cli.ts ci publish-user-service --service decision-center --commit <full-sha>",
|
||||
"bun scripts/cli.ts ci publish-user-service --service frontend --commit <full-sha>",
|
||||
"bun scripts/cli.ts ci run-dev-e2e --wait-ms 600000",
|
||||
"bun scripts/cli.ts ci logs <runId-or-pipelineRun> [--provider-id G14] [--tail-lines 80]",
|
||||
"bun scripts/cli.ts ci cleanup-runs --provider-id D601 --min-age-minutes 60 --limit 50 --dry-run",
|
||||
"bun scripts/cli.ts ci cleanup-runs --provider-id D601 --min-age-minutes 60 --limit 50 --confirm",
|
||||
"bun scripts/cli.ts ci cleanup-failed-pods --provider-id D601 --namespace unidesk-ci --min-age-minutes 60 --dry-run",
|
||||
"bun scripts/cli.ts ci cleanup-failed-pods --provider-id D601 --namespace unidesk-ci --min-age-minutes 60 --confirm",
|
||||
],
|
||||
tekton: {
|
||||
pipelineVersion: tektonPipelineVersion,
|
||||
triggersVersion: tektonTriggersVersion,
|
||||
sources: {
|
||||
pipeline: tektonPipelineReleaseUrl,
|
||||
triggers: tektonTriggersReleaseUrl,
|
||||
interceptors: tektonTriggersInterceptorsUrl,
|
||||
},
|
||||
targets: {
|
||||
default: "D601",
|
||||
g14: {
|
||||
providerId: "G14",
|
||||
pipelineManifest: g14CiPipelineManifest,
|
||||
nodeSelector: "unidesk.ai/node-id=G14",
|
||||
},
|
||||
},
|
||||
},
|
||||
install: {
|
||||
defaultMode: "async-job",
|
||||
waitFlag: "Use --wait only for explicit synchronous debugging; the default returns a .state/jobs job immediately with install-status follow-up.",
|
||||
statusCommand: "bun scripts/cli.ts ci install-status <jobId|latest>",
|
||||
prewarmDefault: true,
|
||||
skipPrewarm: "Use --skip-prewarm only to refresh Tekton/CI manifests when runtime images are already present or prewarm is blocked by provider root/containerd permissions.",
|
||||
skipTektonInstall: "Use --skip-tekton-install with --skip-prewarm only when Tekton is already installed and only UniDesk CI manifests/triggers need refreshing.",
|
||||
},
|
||||
backendCoreArtifact: {
|
||||
producer: "D601 CI",
|
||||
registry: "127.0.0.1:5000/unidesk/backend-core:<commit>",
|
||||
cdCommand: "bun scripts/cli.ts deploy apply --env prod --service backend-core --commit <full-sha>",
|
||||
},
|
||||
userServiceArtifact: {
|
||||
producer: "D601 CI",
|
||||
command: "bun scripts/cli.ts ci publish-user-service --service <service-id> --commit <full-sha>",
|
||||
transports: {
|
||||
auto: "uses direct-docker for repo-owned code-queue artifacts and Tekton for the remaining services",
|
||||
tekton: "D601 Tekton PipelineRun through backend-core/provider control plane",
|
||||
directDocker: "repo-owned Docker artifact publish without backend-core/database dispatch; no deploy apply, rollout, restart, or active-task mutation",
|
||||
},
|
||||
supportedServices: supportedSourceBuildArtifactIds().filter((serviceId) => serviceId !== "backend-core"),
|
||||
blockedServices: blockedCatalogArtifactIds(),
|
||||
registry: "127.0.0.1:5000/unidesk/<service-id>:<commit>",
|
||||
outputFields: ["serviceId", "sourceCommit", "sourceRepo", "dockerfile", "imageRef", "tag", "digest", "digestRef"],
|
||||
summaryContract: catalog.summaryContract,
|
||||
catalogSummary: catalogSummary(),
|
||||
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 --commit <full-sha>",
|
||||
"bun scripts/cli.ts deploy apply --env prod --service frontend --commit <full-sha>",
|
||||
],
|
||||
},
|
||||
runDevE2E: {
|
||||
defaultTriggerMode: "commit-pinned-ssh-launcher",
|
||||
desiredState: "origin/master:deploy.json#environments.dev",
|
||||
scriptSource: "origin/master:deploy.json#environments.dev.ci",
|
||||
},
|
||||
logs: {
|
||||
defaultCapture: "ssh-stream",
|
||||
dispatchTaskFallback: "--dispatch-task",
|
||||
tailLines: "1..2000",
|
||||
reason: "stream capture avoids backend-core task-result compactJson truncating CI log text before the CLI can extract failure hints",
|
||||
},
|
||||
cleanupRuns: {
|
||||
defaultMode: "dry-run",
|
||||
namespace: "unidesk-ci",
|
||||
selector: "status.phase in Succeeded,Failed",
|
||||
guard: "--confirm required for deletion; Running/Pending pods are never selected",
|
||||
},
|
||||
cleanupFailedPods: {
|
||||
defaultNamespace: "unidesk-ci",
|
||||
defaultMinAgeMinutes: 60,
|
||||
defaultLimit: 50,
|
||||
scope: "Kubernetes pods with status.phase=Failed only; does not touch Running/Pending pods, workloads, PVCs, Secrets, or Tekton resources",
|
||||
defaultMode: "dry-run",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function requireRunId(value: string): string {
|
||||
if (!/^[a-z0-9]([-a-z0-9]{0,46}[a-z0-9])?$/u.test(value)) {
|
||||
throw new Error("ci run-dev-e2e run id must be DNS-safe lowercase alnum/dash, max 48 chars");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
Reference in New Issue
Block a user