diff --git a/README.md b/README.md index 7aefc2d..b88a11f 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ - 生成改动文档同步计划:按变更文件自动提示需要同步的 README、API、AGENTS、docs、Obsidian、skill 和 ktWorkflow 入口。 - 生成多仓库提交/推送计划:按仓库分组、建议提交信息、列出提交和推送前检查。 - 生成远程只读健康检查和数据库同步安全向导:覆盖飞牛 NAS 服务探测、GTID、`.kt-workspace/db-sync` 转储、备份库和行数校验。 -- 生成或执行部署观测:把 Jenkins build、commit、K8s Deployment、Pod、`/health/runtime` 和任务 smoke 汇总成 `.kt-workspace/test-artifacts/deploy-observation` 下的运行态证据。 +- 生成或执行部署观测:把 Jenkins build、`build.xml` SCM revision、日志尾部、K8s Deployment、Pod、`/health/runtime` 和任务 smoke 汇总成 `.kt-workspace/test-artifacts/deploy-observation` 下的运行态证据。 - 生成专项组件工作流:KtTable、BlogArgon、AdminAuth、QQBot、FF14Plugin、NapCatLogin、SystemLog、Knife4jSwagger、FnosK8s 的防踩坑清单和验证点。 - 生成验证进程清理计划:按项目路径和端口给出 PowerShell 检查命令,不直接杀进程。 - 清理历史产物:统一治理 `.kt-workspace` 下的测试/验证产物,按目录最近修改时间只保留最近 3 轮,模板目录永久保留;CLI 默认 dry-run,真实清理必须显式传 `--execute`。 @@ -95,7 +95,7 @@ pnpm run admin-login -- --url http://127.0.0.1:5999/#/auth/login | `kt_business_test_plan` | 生成固化业务链路测试计划,包含 QQBot SSE、FFLogs 和系统日志 | | `kt_blocker_resolution` | 生成或写入卡点固化记录,提醒停止原样重试 | | `kt_remote_health_check` | 生成或执行远程只读健康检查命令 | -| `kt_deploy_observation` | 生成或执行 API 发布后的部署观测,汇总 Jenkins、K8s、Pod、`/health/runtime` 和任务 smoke 证据 | +| `kt_deploy_observation` | 生成或执行 API 发布后的部署观测,汇总 Jenkins SCM revision、K8s、Pod、`/health/runtime` 和任务 smoke 证据 | | `kt_db_sync_plan` | 生成数据库同步安全向导 | | `kt_component_workflow` | 输出专项组件/链路防踩坑工作流,包含 FnosK8s | | `kt_obsidian_context` | 读取 Obsidian 索引上下文,支持按 `module` / `query` 返回模块页、文档矩阵、Canvas 摘要、代码锚点和相关规则文档 | diff --git a/src/selfTest.ts b/src/selfTest.ts index aea08f8..f899e54 100644 --- a/src/selfTest.ts +++ b/src/selfTest.ts @@ -398,6 +398,8 @@ export async function runSelfTest(): Promise { const buildDeployObservationTestSections = (overrides: { desiredReplicas?: number; healthStatus?: string; + jenkinsBuildXml?: string; + logCommit?: string; omitSmoke?: boolean; readyReplicas?: number; smokeExitCode?: number; @@ -410,8 +412,12 @@ export async function runSelfTest(): Promise { "buildNumber=132", "result=SUCCESS", "__KT_SECTION:jenkins_log_tail__", - "Checking out Revision abc1234", + overrides.logCommit === "" + ? "Finished: SUCCESS" + : `Checking out Revision ${overrides.logCommit ?? "abc1234"}`, "Finished: SUCCESS", + "__KT_SECTION:jenkins_build_xml__", + overrides.jenkinsBuildXml ?? "", "__KT_SECTION:deployment_json__", JSON.stringify({ metadata: { generation: 12 }, @@ -531,6 +537,28 @@ export async function runSelfTest(): Promise { throw new Error("deploy observation degraded health self-check failed"); } + const deployObservationBuildXmlCommitEvidence = + normalizeDeployObservationEvidence({ + checkedAt: new Date("2026-06-14T00:00:02.000Z"), + input: deployObservationInput, + sectionMap: buildDeployObservationTestSections({ + jenkinsBuildXml: [ + "", + "", + "abc1234", + "", + "", + ].join("\n"), + logCommit: "", + }), + }); + if ( + deployObservationBuildXmlCommitEvidence.status !== "passed" || + deployObservationBuildXmlCommitEvidence.details.jenkins.commitMatched !== true + ) { + throw new Error("deploy observation build.xml commit self-check failed"); + } + const deployObservationFailedSmokeEvidence = normalizeDeployObservationEvidence({ checkedAt: new Date("2026-06-14T00:00:02.000Z"), @@ -644,6 +672,7 @@ export async function runSelfTest(): Promise { "127.0.0.1:${K3D_API_PORT}", 'rm -f "$KUBECONFIG_TEMP"', 'kubectl --kubeconfig "$KUBECONFIG_ACTIVE"', + "section jenkins_build_xml", ]) { if (!deployObservationCommandText.includes(expected)) { throw new Error(`deploy observation kubeconfig self-check failed: ${expected}`); diff --git a/src/tools/deployObservation.ts b/src/tools/deployObservation.ts index 5042de7..875cca3 100644 --- a/src/tools/deployObservation.ts +++ b/src/tools/deployObservation.ts @@ -332,6 +332,8 @@ function buildRemoteScript(input: NormalizedInput): string { 'printf "buildNumber=%s\\n" "$BUILD_NUMBER"', 'if [ -f "$BUILD_DIR/build.xml" ]; then RESULT="$(grep -Eo "[^<]*" "$BUILD_DIR/build.xml" 2>/dev/null | sed -E "s###g" | tail -1 || true)"; else RESULT=""; fi', 'printf "result=%s\\n" "$RESULT"', + 'section jenkins_build_xml', + 'if [ -f "$BUILD_DIR/build.xml" ]; then grep -E "<(hash|sha1)>[0-9a-fA-F]{7,40}" "$BUILD_DIR/build.xml" 2>/dev/null | head -n 20 || true; else echo "jenkins build.xml not found: $BUILD_DIR/build.xml"; fi', 'section jenkins_log_tail', 'if [ -f "$BUILD_DIR/log" ]; then tail -n 160 "$BUILD_DIR/log"; else echo "jenkins log not found: $BUILD_DIR/log"; fi', 'section deployment_json', @@ -400,6 +402,8 @@ function normalizeJenkinsEvidence( ): DeployObservationJenkinsEvidence { const meta = readKeyValueSection(sectionMap.get('jenkins_meta') || ''); const logTail = sectionMap.get('jenkins_log_tail') || ''; + const buildXmlRevision = sectionMap.get('jenkins_build_xml') || ''; + const commitHaystack = `${logTail}\n${buildXmlRevision}`.toLowerCase(); const finishedStatus = meta.result || logTail.match(/Finished:\s*([A-Z_]+)/i)?.[1]?.toUpperCase() || @@ -409,7 +413,7 @@ function normalizeJenkinsEvidence( return { buildNumber: meta.buildNumber || input.buildNumber || null, commitMatched: expectedCommit - ? logTail.toLowerCase().includes(expectedCommit.toLowerCase()) + ? commitHaystack.includes(expectedCommit.toLowerCase()) : null, expectedCommit, finishedStatus,