This commit is contained in:
2026-10-21 13:22:35 +08:00
parent b4ff441a70
commit 337da6d67c
25 changed files with 528 additions and 43 deletions
+117
View File
@@ -0,0 +1,117 @@
[CmdletBinding()]
param(
[ValidateSet('Compile', 'Focused', 'Module')][string]$Mode = 'Module',
[string]$Modules,
[string]$Tests,
[switch]$DryRun,
[string]$MavenCommand = 'mvn'
)
$ErrorActionPreference = 'Stop'
$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path
$pom = Join-Path $repoRoot 'pom.xml'
# 显式选择当前聚合模块,避免漏传参数时意外触发全仓测试。
function Read-Selection([string]$Value, [string]$Name) {
if ([string]::IsNullOrWhiteSpace($Value)) { throw "$Name is required." }
$items = @($Value.Split(',') | ForEach-Object { $_.Trim() })
if ($items -contains '') { throw "$Name contains an empty selection." }
return @($items | Select-Object -Unique)
}
try {
[xml]$rootPom = Get-Content -LiteralPath $pom -Raw
$selectedModules = @(Read-Selection $Modules 'Modules')
foreach ($module in $selectedModules) {
if ($module -cnotin @($rootPom.project.modules.module)) {
throw "Unknown active module: $module"
}
}
$selectedTests = @()
if ($Mode -eq 'Focused') {
$requestedTests = @(Read-Selection $Tests 'Tests')
# 只接受明确类名,不接受通配符或方法筛选;每个请求必须唯一命中所选模块。
foreach ($requested in $requestedTests) {
if ($requested -cnotmatch '^[A-Za-z_$][A-Za-z0-9_$]*(\.[A-Za-z_$][A-Za-z0-9_$]*)*$') {
throw "Tests must contain exact Java class names: $requested"
}
$matches = @(foreach ($module in $selectedModules) {
$testRoot = Join-Path $repoRoot "$module/src/test/java"
if (-not (Test-Path -LiteralPath $testRoot)) { continue }
foreach ($file in Get-ChildItem -LiteralPath $testRoot -Recurse -File -Filter "$($requested.Split('.')[-1]).java") {
$source = Get-Content -LiteralPath $file.FullName -Raw
$package = [regex]::Match($source, '(?m)^\s*package\s+([\w.]+)\s*;').Groups[1].Value
$className = if ($package) { "$package.$($file.BaseName)" } else { $file.BaseName }
if ($requested -ceq $file.BaseName -or $requested -ceq $className) {
[pscustomobject]@{ module = $module; className = $className }
}
}
})
if ($matches.Count -ne 1) { throw "Test must match exactly one source in selected modules: $requested (matches: $($matches.Count))" }
$selectedTests += $matches[0]
}
} elseif ($Tests) {
throw 'Tests is only supported in Focused mode.'
}
} catch {
Write-Host "INVALID CHECK: $($_.Exception.Message)"
exit 2
}
$mavenArgs = @('-T', '1', '-DforkCount=1', '-DreuseForks=true', '-f', $pom, '-pl', ($selectedModules -join ','), '-am')
if ($Mode -eq 'Compile') {
$mavenArgs += 'test-compile'
} else {
$mavenArgs += 'test'
}
if ($Mode -eq 'Focused') {
# 上游依赖可能没有所选类,允许该模块零命中;执行后逐类核对本轮报告。
$mavenArgs += "-Dtest=$((@($selectedTests.className | Select-Object -Unique)) -join ',')"
$mavenArgs += '-Dsurefire.failIfNoSpecifiedTests=false'
}
Write-Host "Backend check: $Mode; selected modules: $($selectedModules -join ','); upstream dependencies included"
Write-Host 'Downstream consumers are NOT auto-selected; include affected consumers explicitly.'
Write-Host ("Command: {0} {1}" -f $MavenCommand, ($mavenArgs -join ' '))
if ($DryRun) {
Write-Host 'DRY-RUN PASS: selection validated; no tests or compilation executed.'
exit 0
}
# 整批占用现有重型名额;已受保护的批次直接执行,不嵌套申请锁。
if (-not $env:CHONGCHONG_LOCAL_CHECK_OWNER) {
$childArgs = @('pwsh', '-NoProfile', '-File', $PSCommandPath, '-Mode', $Mode, '-Modules', ($selectedModules -join ','), '-MavenCommand', $MavenCommand)
if ($Mode -eq 'Focused') { $childArgs += @('-Tests', $Tests) }
& (Join-Path $PSScriptRoot 'local-check.ps1') -WorkingDirectory $repoRoot -Label "Backend $Mode check" -Command $childArgs
exit $LASTEXITCODE
}
$startedAt = [DateTime]::UtcNow
Push-Location $repoRoot
try {
& $MavenCommand @mavenArgs
$code = $LASTEXITCODE
if ($code -ne 0) { exit $code }
if ($Mode -eq 'Focused') {
foreach ($selection in $selectedTests) {
$reportDir = Join-Path $repoRoot "$($selection.module)/target/surefire-reports"
$executed = 0
if (Test-Path -LiteralPath $reportDir) {
foreach ($report in Get-ChildItem -LiteralPath $reportDir -File -Filter 'TEST-*.xml') {
if ($report.LastWriteTimeUtc -lt $startedAt) { continue }
[xml]$xml = Get-Content -LiteralPath $report.FullName -Raw
$suite = $xml.testsuite
if ($suite.name -ceq $selection.className -or ([string]$suite.name).StartsWith($selection.className + '$', [StringComparison]::Ordinal)) {
if ([int]$suite.failures -gt 0 -or [int]$suite.errors -gt 0) { throw "Failed test report: $($suite.name)" }
$executed += [int]$suite.tests - [int]$suite.skipped
}
}
}
if ($executed -le 0) { throw "No executed tests in fresh reports for $($selection.className). Missing, stale or all-skipped reports cannot pass." }
Write-Host "Verified $($selection.className): $executed executed tests"
}
}
} finally {
Pop-Location
}
Write-Host "Backend $Mode check PASS (not a full regression or HTTP acceptance)"
exit 0