Files
build_infra/CodeMetrics/Report.ps1.in
T
2026-07-28 17:55:29 +08:00

110 lines
5.8 KiB
Plaintext

$ErrorActionPreference = "Stop"
$outputDir = "@PSC_REPORT_OUTPUT_DIR@"
$projectName = "@PSC_REPORT_PROJECT_NAME@"
$paths = [ordered]@{
llvm = "@PSC_REPORT_LLVM_DIR@"
cppcheck = "@PSC_REPORT_CPPCHECK_DIR@"
lizard = "@PSC_REPORT_LIZARD_DIR@"
code_count = "@PSC_REPORT_CODE_COUNT_DIR@"
coupling = "@PSC_REPORT_COUPLING_DIR@"
}
function Read-Summary([string]$Directory) {
$path = Join-Path $Directory "summary.json"
if (!(Test-Path -LiteralPath $path)) {
throw "Metrics summary was not found at $path"
}
return Get-Content -LiteralPath $path -Raw | ConvertFrom-Json
}
function H([object]$Value) {
return [Net.WebUtility]::HtmlEncode([string]$Value)
}
function Metric-Table([string]$Title, [object[]]$Rows, [string[]]$Columns) {
$builder = [Text.StringBuilder]::new()
[void]$builder.Append("<section><h2>$(H $Title)</h2><div class=`"table-wrap`"><table><thead><tr>")
foreach ($column in $Columns) {
[void]$builder.Append("<th>$(H $column)</th>")
}
[void]$builder.Append("</tr></thead><tbody>")
foreach ($row in @($Rows)) {
[void]$builder.Append("<tr>")
foreach ($column in $Columns) {
[void]$builder.Append("<td>$(H $row.$column)</td>")
}
[void]$builder.Append("</tr>")
}
[void]$builder.Append("</tbody></table></div></section>")
return $builder.ToString()
}
$data = [ordered]@{}
foreach ($entry in $paths.GetEnumerator()) {
$data[$entry.Key] = Read-Summary $entry.Value
}
New-Item -ItemType Directory -Force -Path $outputDir | Out-Null
$generatedAt = [DateTimeOffset]::Now.ToString("yyyy-MM-dd HH:mm:ss zzz")
$html = [Text.StringBuilder]::new()
[void]$html.Append(@"
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>$(H $projectName) Engineering Metrics</title>
<style>
:root{font-family:"Segoe UI","Microsoft YaHei",sans-serif;color:#18212b;background:#f4f6f8}
body{margin:0}main{max-width:1500px;margin:auto;padding:28px}
header{display:flex;justify-content:space-between;align-items:flex-end;border-bottom:3px solid #1b6b5a;padding-bottom:16px}
h1{font-size:30px;margin:0}h2{font-size:20px;margin:0 0 12px}
.meta{color:#5d6975}.summary{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;margin:20px 0}
.metric{background:white;border:1px solid #d7dde3;border-left:4px solid #1b6b5a;padding:14px}.metric strong{display:block;font-size:24px}.metric span{color:#5d6975}
section{background:white;border:1px solid #d7dde3;margin:14px 0;padding:16px}.table-wrap{overflow:auto;max-height:520px}
table{border-collapse:collapse;width:100%;font-size:13px}th{position:sticky;top:0;background:#e8eef1;text-align:left}th,td{border-bottom:1px solid #e1e5e9;padding:7px 9px;white-space:nowrap}tr:nth-child(even){background:#fafbfc}
a{color:#075f52}footer{color:#68737d;padding:12px 0}
</style>
</head>
<body><main>
<header><div><h1>$(H $projectName) 软件工程指标</h1><div class="meta">静态分析、复杂度、代码规模与耦合度统一报告</div></div><div class="meta">$(H $generatedAt)</div></header>
<div class="summary">
<div class="metric"><strong>$($data.code_count.totals.code)</strong><span>代码行</span></div>
<div class="metric"><strong>$($data.lizard.functions)</strong><span>函数数</span></div>
<div class="metric"><strong>$($data.lizard.average_ccn)</strong><span>平均圈复杂度</span></div>
<div class="metric"><strong>$($data.llvm.findings)</strong><span>认知复杂度记录</span></div>
<div class="metric"><strong>$($data.coupling.include_edges)</strong><span>内部 include 边</span></div>
<div class="metric"><strong>$($data.cppcheck.findings)</strong><span>Cppcheck 发现</span></div>
</div>
"@)
[void]$html.Append((Metric-Table "语言与代码规模" @($data.code_count.languages) @("Language", "Files", "Code", "Comments", "Blanks", "Total")))
[void]$html.Append((Metric-Table "圈复杂度 Top" @($data.lizard.cyclomatic_top) @("CCN", "NLOC", "Function", "File", "StartLine")))
[void]$html.Append((Metric-Table "认知复杂度 Top" @($data.llvm.top) @("Score", "Function", "File", "Line")))
[void]$html.Append((Metric-Table "文件耦合度 Top" @($data.coupling.file_top) @("Coupling", "Afferent", "Efferent", "Instability", "File")))
[void]$html.Append((Metric-Table "模块耦合度 Top" @($data.coupling.module_top) @("Coupling", "Afferent", "Efferent", "Instability", "Module")))
[void]$html.Append((Metric-Table "Cppcheck 发现" @($data.cppcheck.top) @("Severity", "Id", "Message", "File", "Line")))
[void]$html.Append(@"
<section><h2>依赖图</h2><p><a href="coupling/module_coupling.svg">打开模块耦合 SVG</a></p><p class="meta">循环依赖组件数:$(@($data.coupling.cycles).Count)</p></section>
<footer>原始 JSON、CSV、XML、DOT 和 SVG 均保留在各子目录,可供 CI 或后续基准比较。</footer>
</main></body></html>
"@)
[IO.File]::WriteAllText((Join-Path $outputDir "index.html"), $html.ToString(), [Text.UTF8Encoding]::new($false))
$combined = [ordered]@{
project = $projectName
generated_at = $generatedAt
code_count = $data.code_count
lizard = $data.lizard
llvm = $data.llvm
cppcheck = $data.cppcheck
coupling = $data.coupling
}
[IO.File]::WriteAllText((Join-Path $outputDir "metrics.json"), ($combined | ConvertTo-Json -Depth 12), [Text.UTF8Encoding]::new($false))
$markdown = @(
"# $projectName 软件工程指标"
""
"- 代码行:$($data.code_count.totals.code)"
"- 函数数:$($data.lizard.functions)"
"- 平均圈复杂度:$($data.lizard.average_ccn)"
"- Cppcheck 发现:$($data.cppcheck.findings)"
"- 内部 include 边:$($data.coupling.include_edges)"
""
"详细表格请打开 `index.html`。"
)
[IO.File]::WriteAllLines((Join-Path $outputDir "README.md"), $markdown, [Text.UTF8Encoding]::new($false))
Write-Output "Engineering metrics report: $outputDir"