842d711ed6
用户裁定「我不想看到编号」。测试验证层级这一族的整族清退分三道并行:本笔是**代码与 CI 道** (CI 步骤与门禁输出面),代码注释面另走、文档面由文档道走。 口径(旧 → 语义名 → ASCII 段名,段名只进日志/旗标/job id/文件名): L0 静态门禁 static | L0a 钩子解释器预检 preflight | L0b 提交信息门禁 commitmsg L0c 体积门禁 size | L0.5 主机侧纯逻辑单测 host-unit | L0.5c 覆盖率 coverage - scripts/ci_local.py 43 站点:段标题与 [SUMMARY] 标签改 ASCII 段名(static: / host-unit:),函数 run_l0/run_l05 → run_static_gates/run_host_unit_tests, 收尾「已跑:」列表用段名。旗标改 --static-only / --host-unit-only,**旧旗标 --l0-only / --l05-only 保留为 argparse 别名**(肌肉记忆与既有脚本片段不断档, 实测 --help 两名列出)。 - .gitea/workflows/ci.yml 42 站点:job id l0-gates → static-gates、 l05-host-unit-tests → host-unit-tests;步骤名与 step-summary 标题改语义名; 日志名 l0-pre-commit.log → static-pre-commit.log、l05-<模块>.log → host-unit-<模块>.log;::error::/::notice:: 文案同步。yaml.safe_load 核过 两个 job id 与步骤名。 host-unit-tests;步骤名与 step-summary 标题改语义名;日志名 l0-pre-commit.log → static-pre-commit.log、l05-<模块>.log → host-unit-<模块>.log;::error::/::notice:: 文案同步。yaml.safe_load 核过两个 job id 与步骤名。 - 门禁脚本 18 站点:check_registration(登记簿理由串 7)、check_test_coverage 5、 README 8、check_generated_fresh 2、ram_baseline 2、check_size_gate 1、 ci_find_python.ps1 2、ci_runner_bootstrap.ps1 2、.pre-commit-config.yaml 2、 requirements.txt 1(保持纯 ASCII)。 - skills 7 站点:task-worktree(含 [SUMMARY] 样例两行)、mem-budget、ui-verify、 task_worktree.py 的实跑标签。 - AGENTS.md 3 站点:CI 段「只跑静态门禁 + 主机侧纯逻辑单测」、自查命令段、 「2026-10-11 静态门禁全灭」事件名。 - 归档:编号治理历史.md 新增 §10 换算表 + **撞族警示**(同形 L0/L1/L2/L3 还属 UI 设计 令牌层 / UI 菜单层级 / 采集链 / 链路时延段 / CubeMX 三层 / 硬件位号与 FTP 应答字面量 等六个族,其中 6 处在字符串字面量里,改了就是改行为——故全程只按行内置换、先判族)。 - docs/产品需求 §7.4 测试分层表:去号 + 顺带修掉上一批**错族替换疤**(该表 L1/L2 行曾被 采集链层名「语义取数与有效性 / 全周傅氏相量」「保护判据」顶替,现按内容改写为板端测试 套件 / 主机侧回归两行)。同文档 §1.5 G5 判据行同步。 门禁:ci_local --help 两面旗标并列;py_compile 7 个 .py 全过;yaml 解析通过; check_ids_new --worktree rc=0;git diff --check 干净;17 个改动文件 FFFD=0、无 CR、 BOM 与原文件一致(含 requirements.txt 纯 ASCII)。本族无机器识别面(单字母+数字是 新增行门禁的自述盲区),口径来自自建逐行扫描器,复扫本族形态归零。 - 交接说明:文档道 teammate 在改 CI 指南时中断,剩余 9 处双写疤与 29 处 CI 标识 (job id / 日志名 / 汇总行字面量)由 Lead 接手改完,逐处仍走断言式行内置换。
180 lines
7.3 KiB
PowerShell
180 lines
7.3 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Pick a Python interpreter that actually works, for the CI jobs (and for
|
|
local use). Prints diagnostics with Write-Host and emits ONLY the chosen
|
|
interpreter path on the success stream, so a caller can capture it:
|
|
|
|
$py = & './scripts/ci_find_python.ps1' -NeedPreCommit -WriteEnv
|
|
|
|
.DESCRIPTION
|
|
Why this file exists (2026-10-11 CI incident):
|
|
|
|
The DTU_* env-var refactor moved the interpreter probe inline into
|
|
.gitea/workflows/ci.yml and narrowed it to two candidates
|
|
(PATH python + repo .venv). On the Windows runner BOTH are dead ends:
|
|
|
|
* PATH python for the SYSTEM account is C:\msys64\ucrt64\bin\python.exe,
|
|
which has no pre-commit module;
|
|
* the repo .venv is gitignored, so it does not exist in a fresh runner
|
|
workspace at all.
|
|
|
|
The interpreter that does work (a machine-wide install such as
|
|
C:\ProgramData\anaconda3\python.exe) was no longer probed, and no
|
|
machine-level DTU_PRECOMMIT_PYTHON had ever been set -> every static-gate job died
|
|
in "environment check" before running a single hook.
|
|
|
|
So discovery lives here now: one implementation, shared by both CI jobs and
|
|
runnable offline, and it keeps the well-known machine-wide install
|
|
locations as fallbacks.
|
|
|
|
Probe order (see the DTU_* local-tool-path plan under docs/ -- this file is
|
|
kept pure ASCII on purpose: PS 5.1 decodes BOM-less files as CP936):
|
|
1. DTU_PRECOMMIT_PYTHON -- explicit override. If it is set but the file
|
|
is missing, or it cannot satisfy the requirement, this script FAILS
|
|
with the variable name and does NOT silently fall back.
|
|
2. python on PATH
|
|
3. <repo>\.venv\Scripts\python.exe
|
|
4. well-known machine-wide installs (Program Files / ProgramData /
|
|
%LOCALAPPDATA%\Programs\Python), newest version first
|
|
|
|
.PARAMETER NeedPreCommit
|
|
Require the interpreter to expose the pre-commit module (static gates need it).
|
|
Probed with `-s` (no user site-packages) on purpose: the runner service
|
|
runs as SYSTEM, which cannot see a USER-scope site install at all, so only
|
|
an interpreter that works without user-site is accepted.
|
|
|
|
.PARAMETER WriteEnv
|
|
Append PYTHON=<path> to $env:GITHUB_ENV so later steps can use $env:PYTHON.
|
|
Written as ASCII: Out-File's PS 5.1 default is UTF-16LE, which appends
|
|
foreign-encoded lines to a file other steps also append to.
|
|
|
|
.OUTPUTS
|
|
The chosen python.exe path (single line, success stream).
|
|
|
|
.NOTES
|
|
Keep this file pure ASCII -- Windows PowerShell 5.1 decodes BOM-less files
|
|
as CP936, and non-ASCII bytes break string quoting (same trap as ci.yml).
|
|
Exit codes: 0 = found, 2 = no usable interpreter / bad DTU_* override.
|
|
#>
|
|
param(
|
|
[switch]$NeedPreCommit,
|
|
[switch]$WriteEnv
|
|
)
|
|
|
|
# Native probes write to stderr; the runner injects $ErrorActionPreference
|
|
# ='Stop', which would turn that into a terminating NativeCommandError and
|
|
# abort the probe loop before the next candidate is tried.
|
|
$ErrorActionPreference = 'Continue'
|
|
|
|
function Test-Interpreter {
|
|
param([string]$Exe, [bool]$RequirePreCommit)
|
|
|
|
if ([string]::IsNullOrWhiteSpace($Exe)) { return $false }
|
|
if (-not (Test-Path -LiteralPath $Exe -PathType Leaf)) { return $false }
|
|
|
|
$saved = $ErrorActionPreference
|
|
$ErrorActionPreference = 'Continue'
|
|
try {
|
|
if ($RequirePreCommit) {
|
|
& $Exe -s -m pre_commit --version 2>&1 | Out-Null
|
|
}
|
|
else {
|
|
& $Exe --version 2>&1 | Out-Null
|
|
}
|
|
return ($LASTEXITCODE -eq 0)
|
|
}
|
|
catch {
|
|
return $false
|
|
}
|
|
finally {
|
|
$ErrorActionPreference = $saved
|
|
}
|
|
}
|
|
|
|
$repoRoot = Split-Path -Parent $PSScriptRoot
|
|
$require = [bool]$NeedPreCommit
|
|
$what = if ($require) { 'pre-commit' } else { 'a runnable interpreter' }
|
|
|
|
# --- 1. explicit override: honour it or fail loudly -------------------------
|
|
$explicit = $env:DTU_PRECOMMIT_PYTHON
|
|
if (-not [string]::IsNullOrWhiteSpace($explicit)) {
|
|
$explicit = $explicit.Trim()
|
|
if (-not (Test-Path -LiteralPath $explicit -PathType Leaf)) {
|
|
Write-Host "::error::DTU_PRECOMMIT_PYTHON is set but does not exist: $explicit"
|
|
Write-Host '::error::fix the variable (full path to a python.exe) or unset it to use auto-discovery'
|
|
exit 2
|
|
}
|
|
if (-not (Test-Interpreter -Exe $explicit -RequirePreCommit $require)) {
|
|
Write-Host "::error::DTU_PRECOMMIT_PYTHON does not provide $what (probed without user-site, i.e. SYSTEM-visible): $explicit"
|
|
Write-Host '::error::fix the variable, or unset it to use auto-discovery'
|
|
exit 2
|
|
}
|
|
Write-Host "using python (DTU_PRECOMMIT_PYTHON): $explicit"
|
|
if ($WriteEnv -and $env:GITHUB_ENV) {
|
|
"PYTHON=$explicit" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding ascii
|
|
}
|
|
Write-Output $explicit
|
|
exit 0
|
|
}
|
|
|
|
# --- 2..4 auto-discovery ----------------------------------------------------
|
|
$programFiles = $env:ProgramFiles
|
|
$programFilesX86 = ${env:ProgramFiles(x86)}
|
|
if ([string]::IsNullOrWhiteSpace($programFiles)) { $programFiles = 'C:\Program Files' }
|
|
if ([string]::IsNullOrWhiteSpace($programFilesX86)) { $programFilesX86 = 'C:\Program Files (x86)' }
|
|
|
|
$candidates = @()
|
|
|
|
$onPath = Get-Command python -ErrorAction SilentlyContinue
|
|
if ($onPath) { $candidates += $onPath.Source }
|
|
|
|
$candidates += (Join-Path $repoRoot '.venv\Scripts\python.exe')
|
|
|
|
# Newest first: a fresh install is the usual intent.
|
|
foreach ($ver in @('Python313', 'Python312', 'Python311', 'Python310')) {
|
|
$candidates += (Join-Path $programFiles "$ver\python.exe")
|
|
$candidates += (Join-Path $programFilesX86 "$ver\python.exe")
|
|
if ($env:LOCALAPPDATA) {
|
|
$candidates += (Join-Path $env:LOCALAPPDATA "Programs\Python\$ver\python.exe")
|
|
}
|
|
}
|
|
|
|
# Machine-wide distributions (these are what the runner actually had).
|
|
if ($env:ProgramData) {
|
|
foreach ($dist in @('anaconda3', 'miniconda3')) {
|
|
$candidates += (Join-Path $env:ProgramData "$dist\python.exe")
|
|
}
|
|
}
|
|
$candidates += 'C:\ProgramData\anaconda3\python.exe'
|
|
$candidates += 'C:\ProgramData\miniconda3\python.exe'
|
|
|
|
$tried = New-Object System.Collections.Generic.List[string]
|
|
$chosen = $null
|
|
foreach ($c in $candidates) {
|
|
if ([string]::IsNullOrWhiteSpace($c)) { continue }
|
|
if ($tried.Contains($c)) { continue }
|
|
$tried.Add($c) | Out-Null
|
|
if (Test-Interpreter -Exe $c -RequirePreCommit $require) { $chosen = $c; break }
|
|
}
|
|
|
|
if (-not $chosen) {
|
|
Write-Host "::error::no Python providing $what found (tried `$DTU_PRECOMMIT_PYTHON`, PATH python, repo .venv, and the well-known machine-wide installs)"
|
|
foreach ($t in $tried) { Write-Host " tried: $t" }
|
|
Write-Host '::error::note: the runner service runs as SYSTEM, so a USER-scope `pip install --user pre-commit` is invisible to it'
|
|
Write-Host '::error::fix: set a MACHINE-level DTU_PRECOMMIT_PYTHON (see scripts/ci_runner_bootstrap.ps1 -SetEnv), or install pre-commit into a machine-wide interpreter'
|
|
exit 2
|
|
}
|
|
|
|
Write-Host "using python (auto-discovered): $chosen"
|
|
# Out-Host, NOT the pipeline: a native command's stdout joins the success
|
|
# stream, which would pollute the single-line path the caller captures.
|
|
& $chosen --version 2>&1 | Out-Host
|
|
if ($require) { & $chosen -s -m pre_commit --version 2>&1 | Out-Host }
|
|
|
|
if ($WriteEnv -and $env:GITHUB_ENV) {
|
|
"PYTHON=$chosen" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding ascii
|
|
}
|
|
|
|
Write-Output $chosen
|
|
exit 0
|