(repoPath)
| 411 | const SKIP_DIRS = new Set(["node_modules", "target", "build", "dist", "out", "bin", ".git"]); |
| 412 | |
| 413 | async function buildAssessment(repoPath) { |
| 414 | const rootPom = await readText(join(repoPath, "pom.xml")); |
| 415 | let rootGradle = await readText(join(repoPath, "build.gradle")); |
| 416 | if (!rootGradle) rootGradle = await readText(join(repoPath, "build.gradle.kts")); |
| 417 | const antBuild = await readText(join(repoPath, "build.xml")); |
| 418 | |
| 419 | // Union one level of modules so multi-module Maven, Gradle subprojects, and |
| 420 | // monorepos report the real Java version / dependencies — not just whatever |
| 421 | // the (often dependency-free) aggregator root pom declares. |
| 422 | const childPoms = []; |
| 423 | const childGradles = []; |
| 424 | try { |
| 425 | const entries = await readdir(repoPath, { withFileTypes: true }); |
| 426 | for (const e of entries) { |
| 427 | if (!e.isDirectory() || e.name.startsWith(".") || SKIP_DIRS.has(e.name)) continue; |
| 428 | const cp = await readText(join(repoPath, e.name, "pom.xml")); |
| 429 | if (cp) childPoms.push(cp); |
| 430 | let cg = await readText(join(repoPath, e.name, "build.gradle")); |
| 431 | if (!cg) cg = await readText(join(repoPath, e.name, "build.gradle.kts")); |
| 432 | if (cg) childGradles.push(cg); |
| 433 | } |
| 434 | } catch { |
| 435 | /* ignore */ |
| 436 | } |
| 437 | |
| 438 | const allPom = [rootPom, ...childPoms].filter(Boolean).join("\n"); |
| 439 | const allGradle = [rootGradle, ...childGradles].filter(Boolean).join("\n"); |
| 440 | const buildText = `${allPom}\n${allGradle}\n${antBuild || ""}`; |
| 441 | const hasMaven = !!(rootPom || childPoms.length); |
| 442 | const hasGradle = !!(rootGradle || childGradles.length); |
| 443 | const buildTool = hasMaven ? "Maven" : hasGradle ? "Gradle" : antBuild ? "Ant" : null; |
| 444 | const springBoot = /spring-boot/i.test(buildText); |
| 445 | const springVersion = (() => { |
| 446 | const m = buildText.match(/spring-boot[^>]*?<version>\s*([\d.]+[\w.-]*)\s*</i); |
| 447 | return m ? m[1] : null; |
| 448 | })(); |
| 449 | |
| 450 | const detectedKeys = detectDependencies(buildText); |
| 451 | // Ant is identified by its build file, not a content substring (avoids the |
| 452 | // old "ant" false positives), so flag it from the resolved build tool. |
| 453 | if (buildTool === "Ant" && !detectedKeys.includes("ant")) detectedKeys.push("ant"); |
| 454 | |
| 455 | return { |
| 456 | buildTool, |
| 457 | javaVersion: detectJavaVersion(allPom, allGradle), |
| 458 | springBoot, |
| 459 | springVersion, |
| 460 | hasDockerfile: await findDockerfile(repoPath), |
| 461 | hasMavenWrapper: |
| 462 | (await exists(join(repoPath, "mvnw"))) || (await exists(join(repoPath, "mvnw.cmd"))), |
| 463 | hasGradleWrapper: |
| 464 | (await exists(join(repoPath, "gradlew"))) || (await exists(join(repoPath, "gradlew.bat"))), |
| 465 | detectedKeys, |
| 466 | }; |
| 467 | } |
| 468 | |
| 469 | /** |
| 470 | * Scan a repo and produce the full cockpit state snapshot. |
no test coverage detected