CI:补产物存档与结果汇总,明示体积门禁盲区(S3+S14)
This commit is contained in:
+130
-8
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user