Files
pi_mcps/zoo_backup/home/tools/mvn_test.ts
T
2026-06-24 19:27:14 +02:00

69 lines
2.9 KiB
TypeScript

import { parametersSchema as z, defineCustomTool } from "@roo-code/types"
import { spawnSync } from "child_process"
import { readdirSync, readFileSync, existsSync } from "fs"
import { join } from "path"
export default defineCustomTool({
name: "mvn_test",
description: "Run Maven tests for a module in a multi-module project. Parses surefire XML reports and returns structured pass/fail results.",
parameters: z.object({
worktreePath: z.string().describe("Path to the project root or worktree (e.g. /path/to/my-project)"),
module: z.string().describe("Module path relative to java/, e.g. modules/cs-modules/my-module"),
testClass: z.string().optional().describe("Specific test class to run, e.g. MyServiceTest"),
}),
async execute({ worktreePath, module, testClass }) {
const pomPath = join(worktreePath, "java", "pom.xml")
if (!existsSync(pomPath)) {
return `Error: pom.xml not found at ${pomPath}`
}
const args = ["test", "-pl", `java/${module}`, "-f", pomPath, "--batch-mode", "-q"]
if (testClass) {
args.push(`-Dtest=${testClass}`)
}
const result = spawnSync("mvn", args, {
encoding: "utf-8",
timeout: 300000,
cwd: worktreePath,
maxBuffer: 10 * 1024 * 1024,
})
const surefireDir = join(worktreePath, "java", module, "target", "surefire-reports")
const summary = { total: 0, passed: 0, failed: 0, errors: 0, skipped: 0, failures: [] as string[] }
if (existsSync(surefireDir)) {
try {
const xmlFiles = readdirSync(surefireDir).filter(f => f.startsWith("TEST-") && f.endsWith(".xml"))
for (const xmlFile of xmlFiles) {
const content = readFileSync(join(surefireDir, xmlFile), "utf-8")
const testsMatch = content.match(/tests="(\d+)"/)
const failuresMatch = content.match(/failures="(\d+)"/)
const errorsMatch = content.match(/errors="(\d+)"/)
const skippedMatch = content.match(/skipped="(\d+)"/)
if (testsMatch) summary.total += parseInt(testsMatch[1])
if (failuresMatch) summary.failed += parseInt(failuresMatch[1])
if (errorsMatch) summary.errors += parseInt(errorsMatch[1])
if (skippedMatch) summary.skipped += parseInt(skippedMatch[1])
const failureMatches = content.matchAll(/<failure[^>]*message="([^"]*)"[^>]*>/g)
for (const m of failureMatches) {
summary.failures.push(`${xmlFile.replace("TEST-", "").replace(".xml", "")}: ${m[1]}`)
}
}
summary.passed = summary.total - summary.failed - summary.errors - summary.skipped
} catch (e) {
// surefire parsing failed, continue with what we have
}
}
return JSON.stringify({
buildStatus: result.status === 0 ? "SUCCESS" : "FAILURE",
exitCode: result.status,
summary,
lastOutput: (result.status !== 0 ? (result.stderr || result.stdout || "") : "").split("\n").slice(-15).join("\n"),
}, null, 2)
},
})