CI:补产物存档与结果汇总,明示体积门禁盲区(S3+S14)
CI / L0 静态门禁 (pre-commit) (push) Successful in 58s
CI / L0.5 主机侧单测 (MSVC) (push) Successful in 19s

This commit is contained in:
2026-10-02 11:55:31 +08:00
parent fac9d1c409
commit f3befaed08
5 changed files with 268 additions and 20 deletions
+130 -8
View File
@@ -14,6 +14,17 @@
# 无 `@build` 即无 `.map`。故本 workflow 在**检测不到 .map 时自动跳过该钩子**
# (见下方 "决定跳过哪些钩子" 步骤),有 .map 的 runner(如自建带 Keil 的机器)则照常跑。
#
# 🔴 门禁盲区声明(S14,2026-10-02):跳过 `mem-numbers` 意味着 **CI 不守 Flash/RAM 体积门禁**。
# 体积变更(新增任务/缓冲/代码)不会在 CI 被拦下;必须靠**本地 `@build` 后**
# `python scripts/check_mem_numbers.py --scan` 兜底。故该跳过以 `::warning::` 明示
# (不是弱化的 `::notice::`),并写入 job step-summary 的醒目行。
#
# 产物存档(S3,2026-10-02):两个 job 把关键输出 `Tee-Object` 到 `ci-artifacts/*.log`,
# 并写 $GITHUB_STEP_SUMMARY(Gitea UI 直接可见)+ `::notice::` 汇总行。
# **刻意不用 `actions/upload-artifact`**——内网可能拉不到外层 action(见 CI配置指南 §4.3);
# 零依赖方案下日志留在 runner 工作区,UI 通过 step-summary 即可排障。
# ⚠️ `ci-artifacts/` 已 gitignore(运行时产物)。
#
# 触发:push(除纯文档路径外)与 pull_request。
#
# 🔴 shell 用 `powershell` 而非 `pwsh`(2026-10-02 实测修正):
@@ -156,13 +167,27 @@ jobs:
run: |
# mem-numbers fact source is the Keil build artifact .map (gitignored).
# No .map => this hook cannot run => skip (not "pass", but "not applicable").
#
# S14 (2026-10-02): make this GAP loud. mem-numbers is the ONLY gate that
# checks docs/memory numbers against the real .map (Flash/RAM size). When
# it is skipped, CI effectively does NOT guard the size budget -- a silent
# ::notice:: was too easy to miss. So:
# - emit ::warning:: (not ::notice::) so it shows in the run summary
# - write a machine-readable marker file for the summary step
# - append a bold line to the job step-summary
$map = Get-ChildItem -Path 'MDK-ARM' -Recurse -Filter '*.map' -ErrorAction SilentlyContinue
if ($map) {
Write-Host "found .map: $($map[0].FullName) -- mem-numbers runs normally"
"value=" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
"sizegate=on" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
"> Volume gate (mem-numbers): RAN (.map present)" |
Out-File -FilePath $env:GITHUB_STEP_SUMMARY -Append -Encoding utf8
} else {
Write-Host "::notice::no .map found (no Keil build) -- skipping mem-numbers hook"
Write-Host "::warning::no .map found (no Keil build) -- SKIPPING mem-numbers, so the Flash/RAM size gate does NOT run in CI. Size changes are NOT caught here; verify locally with 'python scripts/check_mem_numbers.py --scan' after a Keil build."
"value=mem-numbers" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
"sizegate=off" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
"> :warning: Volume gate (mem-numbers): **NOT RUN** -- no `.map` (no Keil build)." |
Out-File -FilePath $env:GITHUB_STEP_SUMMARY -Append -Encoding utf8
}
- name: 运行 L0 门禁(--all-files)
@@ -170,13 +195,55 @@ jobs:
env:
SKIP: ${{ steps.skip.outputs.value }}
run: |
# Pure ASCII only (see file header). Capture output to an artifact file
# AND to the console (Tee-Object), so a failed run is debuggable from the
# Gitea UI without inspecting runner disk.
#
# CAUTION: the runner injects $ErrorActionPreference='Stop'. With `2>&1 |`,
# a native command's stderr becomes an ErrorRecord -> under 'Stop' that
# would ABORT the pipeline. Relax the preference around the pipeline and
# restore it afterwards (same pattern as the env-check step above).
New-Item -ItemType Directory -Force -Path 'ci-artifacts' | Out-Null
$log = 'ci-artifacts\l0-pre-commit.log'
if ($env:SKIP) { Write-Host "SKIP=$env:SKIP" }
& $env:PYTHON -s -m pre_commit run --all-files --show-diff-on-failure
if ($LASTEXITCODE -ne 0) {
Write-Host "::error::L0 static gates failed (see output above)"
exit $LASTEXITCODE
$saved = $ErrorActionPreference
$ErrorActionPreference = 'Continue'
& $env:PYTHON -s -m pre_commit run --all-files --show-diff-on-failure 2>&1 |
Tee-Object -FilePath $log
$rc = $LASTEXITCODE
$ErrorActionPreference = $saved
# Summarize hook results: count Passed / Failed / Skipped lines.
$lines = Get-Content $log -ErrorAction SilentlyContinue
$passed = @($lines | Select-String -Pattern 'Passed$').Count
$failed = @($lines | Select-String -Pattern 'Failed$').Count
$skipd = @($lines | Select-String -Pattern 'Skipped$').Count
$summary = "L0: pre-commit hooks -- passed=$passed failed=$failed skipped=$skipd (log: $log)"
Write-Host "::notice::$summary"
Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "### L0 static gates" -Encoding utf8
Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value $summary -Encoding utf8
if ($rc -ne 0) {
Write-Host "::error::L0 static gates failed (see output above and $log)"
exit $rc
}
- name: 归档 L0 日志(供下载/排障)
if: always()
shell: powershell
run: |
# S3: zero-dependency artifact archival. We do NOT use
# actions/upload-artifact (inner networks may not fetch outer actions);
# instead we keep the log on the runner AND surface its path + tail in
# the step summary, so the UI is self-sufficient for triage.
if (Test-Path 'ci-artifacts\l0-pre-commit.log') {
$size = (Get-Item 'ci-artifacts\l0-pre-commit.log').Length
Write-Host "archived: ci-artifacts/l0-pre-commit.log ($size bytes)"
Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "" -Encoding utf8
Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "Archived log: ``ci-artifacts/l0-pre-commit.log`` ($size bytes on runner)" -Encoding utf8
}
Write-Host "::notice::L0 artifacts kept on runner at: ci-artifacts\l0-pre-commit.log"
# ------------------------------------------------------------------
# L0.5:主机侧纯逻辑单测(零硬件;缺 MSVC 则跳过)
# ------------------------------------------------------------------
@@ -213,6 +280,7 @@ jobs:
}
- name: 运行主机侧单测
id: l05
if: steps.msvc.outputs.value == 'yes'
shell: powershell
run: |
@@ -229,6 +297,8 @@ jobs:
if (-not $py) { Write-Host "::error::no python found"; exit 1 }
Write-Host "using python: $py"
New-Item -ItemType Directory -Force -Path 'ci-artifacts' | Out-Null
# Iterate test/host/*/run_unit_test.py (each module ships its own runner via common harness)
$runners = Get-ChildItem -Path 'test/host' -Recurse -Filter 'run_unit_test.py' |
Sort-Object FullName
@@ -237,22 +307,74 @@ jobs:
exit 0
}
$fail = 0
$runnerCount = 0
$sumPass = 0
$sumTotal = 0
# Relax preference around each `2>&1 | Tee-Object` pipeline (native stderr
# becomes ErrorRecord -> 'Stop' would abort). See L0 step for details.
$savedPref = $ErrorActionPreference
foreach ($r in $runners) {
$runnerCount++
$name = $r.Directory.Name
$log = "ci-artifacts\l05-$name.log"
Write-Host "================================"
Write-Host "run: $($r.FullName)"
Write-Host "================================"
& $py $r.FullName
if ($LASTEXITCODE -ne 0) {
Write-Host "::error::unit test failed: $($r.FullName) (exit $LASTEXITCODE)"
$ErrorActionPreference = 'Continue'
& $py $r.FullName 2>&1 | Tee-Object -FilePath $log
$rc = $LASTEXITCODE
$ErrorActionPreference = $savedPref
# Parse the module's own summary line, e.g.
# "=== System Clock Tests: 100/100 PASSED (failed=0) ==="
$m = Select-String -Path $log -Pattern ': (\d+)/(\d+) PASSED \(failed=(\d+)\)' -ErrorAction SilentlyContinue |
Select-Object -Last 1
if ($m) {
$sumPass += [int]$m.Matches[0].Groups[1].Value
$sumTotal += [int]$m.Matches[0].Groups[2].Value
Write-Host ("::notice::{0}: {1}" -f $name, $m.Matches[0].Value.Trim())
} else {
Write-Host "::warning::$name produced no '=== ... N/M PASSED ===' summary line"
}
if ($rc -ne 0) {
Write-Host "::error::unit test failed: $($r.FullName) (exit $rc)"
$fail = 1
}
}
$agg = "L0.5: $runnerCount runner(s), $sumPass/$sumTotal assertions passed, fail=$fail"
Write-Host "::notice::$agg"
Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "### L0.5 host-side unit tests" -Encoding utf8
Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value $agg -Encoding utf8
"count=$runnerCount" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
"agg=$agg" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
exit $fail
- name: 归档 L0.5 日志(供下载/排障)
if: always()
shell: powershell
run: |
# S3: same zero-dependency archival as L0.
if (Test-Path 'ci-artifacts') {
$logs = Get-ChildItem -Path 'ci-artifacts' -Filter '*.log' -ErrorAction SilentlyContinue
foreach ($f in $logs) {
Write-Host "archived: $($f.FullName) ($($f.Length) bytes)"
}
$names = ($logs | ForEach-Object { '``' + $_.Name + '``' }) -join ', '
if ($names) {
Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "" -Encoding utf8
Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "Archived logs on runner: $names" -Encoding utf8
}
} else {
Write-Host "no ci-artifacts directory (L0.5 skipped or failed early)"
}
- name: L0.5 跳过说明
if: steps.msvc.outputs.value == 'no'
shell: powershell
run: |
Write-Host "L0.5 skipped: runner has no MSVC."
Write-Host "Local equivalent: & '.venv\Scripts\python.exe' scripts/ci_local.py"
Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "### L0.5 host-side unit tests" -Encoding utf8
Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value ":warning: **NOT RUN** -- runner has no MSVC (VS C++ toolchain)." -Encoding utf8
exit 0