mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-05-07 00:39:00 +08:00
fix(godot): 清理 Godot 模块与测试项目告警
- 优化 GodotYamlConfigEnvironment 目录枚举逻辑,拆分 helper 以消除 MA0051 - 修复 Godot 生命周期 await 的上下文声明,显式保留主线程同步上下文 - 更新 Godot.Tests 异步断言与字符串 comparer,用例项目构建收敛到 0 warning(s) - 补充 analyzer-warning-reduction 跟踪与 trace,记录 RP-053 的批次结果与验证
This commit is contained in:
parent
63f563cd49
commit
6ff07ad3d9
@ -20,7 +20,7 @@ public sealed class AbstractArchitectureModuleInstallationTests
|
||||
var module = new RecordingGodotModule();
|
||||
|
||||
var exception = Assert.ThrowsAsync<InvalidOperationException>(async () =>
|
||||
await architecture.InstallGodotModuleForTestAsync(module));
|
||||
await architecture.InstallGodotModuleForTestAsync(module).ConfigureAwait(false));
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
|
||||
@ -197,7 +197,7 @@ public sealed class GodotYamlConfigLoaderTests
|
||||
var loader = CreateLoader(isEditor: false);
|
||||
|
||||
var exception = Assert.ThrowsAsync<ConfigLoadException>(async () =>
|
||||
await loader.LoadAsync(new ConfigRegistry()));
|
||||
await loader.LoadAsync(new ConfigRegistry()).ConfigureAwait(false));
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
@ -225,7 +225,7 @@ public sealed class GodotYamlConfigLoaderTests
|
||||
configureLoader: static _ => { });
|
||||
|
||||
var exception = Assert.ThrowsAsync<ArgumentException>(async () =>
|
||||
await loader.LoadAsync(new ConfigRegistry()));
|
||||
await loader.LoadAsync(new ConfigRegistry()).ConfigureAwait(false));
|
||||
|
||||
Assert.That(exception!.ParamName, Is.EqualTo("relativePath"));
|
||||
}
|
||||
@ -254,7 +254,7 @@ public sealed class GodotYamlConfigLoaderTests
|
||||
configureLoader: static _ => { });
|
||||
|
||||
var exception = Assert.ThrowsAsync<ArgumentException>(async () =>
|
||||
await loader.LoadAsync(new ConfigRegistry()));
|
||||
await loader.LoadAsync(new ConfigRegistry()).ConfigureAwait(false));
|
||||
|
||||
Assert.That(exception!.ParamName, Is.EqualTo("relativePath"));
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using GFramework.Godot.Text;
|
||||
|
||||
namespace GFramework.Godot.Tests.Text;
|
||||
@ -25,7 +26,7 @@ public sealed class RichTextMarkupTests
|
||||
[Test]
|
||||
public void Effect_Should_Sort_Environment_Parameters_By_Key()
|
||||
{
|
||||
var env = new Dictionary<string, object?>
|
||||
var env = new Dictionary<string, object?>(StringComparer.Ordinal)
|
||||
{
|
||||
["tick"] = 0.1f,
|
||||
["speed"] = 4
|
||||
@ -53,7 +54,7 @@ public sealed class RichTextMarkupTests
|
||||
[Test]
|
||||
public void Effect_Should_Reject_Invalid_Environment_Key_Tokens()
|
||||
{
|
||||
var env = new Dictionary<string, object?>
|
||||
var env = new Dictionary<string, object?>(StringComparer.Ordinal)
|
||||
{
|
||||
["bad key"] = 1
|
||||
};
|
||||
|
||||
@ -112,8 +112,8 @@ public abstract class AbstractArchitecture(
|
||||
// 在附加流程完成前先登记模块,保证后续任一步失败时仍能参与架构销毁阶段的清理。
|
||||
_extensions.Add(module);
|
||||
|
||||
// 等待锚点准备就绪,并保持 Godot 同步上下文,以便后续附加逻辑安全访问节点 API。
|
||||
await anchor.WaitUntilReadyAsync();
|
||||
// 显式保留 Godot 同步上下文,确保后续 AddChild 和 OnAttach 仍在节点可访问的主线程执行。
|
||||
await anchor.WaitUntilReadyAsync().ConfigureAwait(true);
|
||||
|
||||
// 延迟调用将扩展节点添加为锚点的子节点
|
||||
anchor.CallDeferred(Node.MethodName.AddChild, module.Node);
|
||||
|
||||
@ -104,7 +104,12 @@ internal sealed class GodotYamlConfigEnvironment
|
||||
|
||||
private static IReadOnlyList<GodotYamlConfigDirectoryEntry>? EnumerateDirectoryCore(string path)
|
||||
{
|
||||
if (!path.IsGodotPath())
|
||||
return path.IsGodotPath()
|
||||
? EnumerateGodotDirectory(path)
|
||||
: EnumerateFileSystemDirectory(path);
|
||||
}
|
||||
|
||||
private static IReadOnlyList<GodotYamlConfigDirectoryEntry>? EnumerateFileSystemDirectory(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -120,25 +125,15 @@ internal sealed class GodotYamlConfigEnvironment
|
||||
Directory.Exists(entryPath)))
|
||||
.ToArray();
|
||||
}
|
||||
catch (IOException)
|
||||
catch (Exception ex) when (IsExpectedDirectoryEnumerationException(ex))
|
||||
{
|
||||
// 非 Godot 路径分支与公开契约保持一致:宿主无法访问目录时返回 null,而不是泄漏底层异常。
|
||||
return null;
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static IReadOnlyList<GodotYamlConfigDirectoryEntry>? EnumerateGodotDirectory(string path)
|
||||
{
|
||||
using var directory = DirAccess.Open(path);
|
||||
if (directory == null)
|
||||
{
|
||||
@ -170,9 +165,15 @@ internal sealed class GodotYamlConfigEnvironment
|
||||
// 目录枚举句柄必须成对结束,避免未来循环体扩展后在异常路径上遗留引擎状态。
|
||||
directory.ListDirEnd();
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
private static bool IsExpectedDirectoryEnumerationException(Exception exception)
|
||||
{
|
||||
return exception is IOException or UnauthorizedAccessException or ArgumentException or NotSupportedException;
|
||||
}
|
||||
|
||||
private static bool FileExistsCore(string path)
|
||||
{
|
||||
return path.IsGodotPath()
|
||||
|
||||
@ -144,7 +144,8 @@ public abstract class SceneBehaviorBase<T> : ISceneBehavior
|
||||
public virtual async ValueTask OnPauseAsync()
|
||||
{
|
||||
if (_scene != null)
|
||||
await _scene.OnPauseAsync();
|
||||
// 暂停后紧接着会修改 Owner 的处理开关,必须回到 Godot 主线程继续执行。
|
||||
await _scene.OnPauseAsync().ConfigureAwait(true);
|
||||
|
||||
// 暂停处理
|
||||
Owner.SetProcess(false);
|
||||
@ -165,7 +166,8 @@ public abstract class SceneBehaviorBase<T> : ISceneBehavior
|
||||
return;
|
||||
|
||||
if (_scene != null)
|
||||
await _scene.OnResumeAsync();
|
||||
// 恢复完成后要立刻重新启用节点处理流程,因此显式保留当前同步上下文。
|
||||
await _scene.OnResumeAsync().ConfigureAwait(true);
|
||||
|
||||
// 恢复处理
|
||||
Owner.SetProcess(true);
|
||||
@ -198,7 +200,8 @@ public abstract class SceneBehaviorBase<T> : ISceneBehavior
|
||||
public virtual async ValueTask OnUnloadAsync()
|
||||
{
|
||||
if (_scene != null)
|
||||
await _scene.OnUnloadAsync();
|
||||
// 卸载后的 QueueFreeX 必须在 Godot 节点线程上调用,不能切走同步上下文。
|
||||
await _scene.OnUnloadAsync().ConfigureAwait(true);
|
||||
|
||||
// 释放节点
|
||||
Owner.QueueFreeX();
|
||||
|
||||
@ -6,36 +6,34 @@
|
||||
|
||||
## 当前恢复点
|
||||
|
||||
- 恢复点编号:`ANALYZER-WARNING-REDUCTION-RP-052`
|
||||
- 当前阶段:`Phase 52`
|
||||
- 恢复点编号:`ANALYZER-WARNING-REDUCTION-RP-053`
|
||||
- 当前阶段:`Phase 53`
|
||||
- 当前焦点:
|
||||
- `2026-04-24` 本轮从当前 PR review 的未解决线程回切到 `GFramework.Game` / `GFramework.Godot.SourceGenerators.Tests`
|
||||
- `UnifiedSettingsFile.Sections` 与 `CloneFile` fallback 已对齐为“可保留原 comparer 时保留,否则显式回退到 `StringComparer.Ordinal`”的文档与实现契约
|
||||
- `AutoRegisterExportedCollectionsGeneratorTests` 中剩余的 `await test.RunAsync();` 已统一补齐 `.ConfigureAwait(false)`,并同步让 `VerifyDiagnosticsAsync` 内部消费异步等待
|
||||
- 当前批次仍需避免混入与 analyzer-warning-reduction 无关的既有工作树改动
|
||||
- `2026-04-24` 本轮按 `$gframework-batch-boot 75` 重新建立当前分支相对 `origin/main` 的 batch 基线,并从整仓 `Release` build 里挑选低风险热点
|
||||
- `GFramework.Godot` 已完成一轮独立 warning 清理:`GodotYamlConfigEnvironment` 的目录枚举逻辑已拆分 helper,`AbstractArchitecture` / `SceneBehaviorBase` 中需要保留 Godot 同步上下文的 await 已显式改为 `.ConfigureAwait(true)`
|
||||
- `GFramework.Godot.Tests` 已同步清理对应测试 warning:异步断言显式使用 `.ConfigureAwait(false)`,`RichTextMarkupTests` 中测试字典显式指定 `StringComparer.Ordinal`
|
||||
- 当前代码批次相对 `origin/main` 的待提交 diff 为 `6` 个文件、`107` 行变更,远低于 `$gframework-batch-boot 75` 的主停止阈值;本轮在这里收口,是因为下一批候选将进入 `GFramework.Game` 等高基线模块,而不再是同等级低风险切片
|
||||
|
||||
## 当前活跃事实
|
||||
|
||||
- 之前记录的 plain `dotnet build` `0 Warning(s)` 属于增量构建假阴性,不能再作为 warning 检查真值
|
||||
- 本轮已完成 `GFramework.Godot.SourceGenerators` warning 清理:clean `Release` build 从 9 个 warning 降至 0 个 warning
|
||||
- 当前已确认解决的文件包括 `BindNodeSignalGenerator.cs`、`GetNodeGenerator.cs`、`GodotProjectMetadataGenerator.cs`、`Registration/AutoRegisterExportedCollectionsGenerator.cs`
|
||||
- 本轮直接执行仓库根目录 `dotnet clean` 仍在 `ValidateSolutionConfiguration` 阶段失败,输出未提供具体 error 文本
|
||||
- 本轮直接执行仓库根目录 `dotnet build` 成功,并给出 `1184 warning(s)` 的真实输出
|
||||
- `GFramework.Godot.SourceGenerators.Tests` 已通过测试辅助模板抽取与 `ConfigureAwait(false)` 修正,当前 `Debug` / `Release` 构建均为 `0 Warning(s)`
|
||||
- 本轮已验证 `dotnet test GFramework.Godot.SourceGenerators.Tests/GFramework.Godot.SourceGenerators.Tests.csproj -c Release --no-build`,结果为 `Passed: 48`
|
||||
- 本轮已把 PR #283 中仍打开的 `UnifiedSettingsDataRepository.cs` comparer 契约线程落到代码与 XML 注释,避免 fallback 语义继续依赖隐式默认 comparer
|
||||
- 本轮已确认 `AutoRegisterExportedCollectionsGeneratorTests` 的 5 处裸 `await test.RunAsync();` 不是当前 Release build 告警来源,但仍作为 PR review 一致性项一并修正
|
||||
- 本轮直接执行仓库根目录 `dotnet build GFramework.sln -c Release` 成功,并给出 `1122 warning(s)` 的当前整仓观测值
|
||||
- `GFramework.Godot/GFramework.Godot.csproj -c Release` 在本轮收尾验证中已达到 `0 Warning(s)`、`0 Error(s)`
|
||||
- `GFramework.Godot.Tests/GFramework.Godot.Tests.csproj -c Release` 在串行复验中已达到 `0 Warning(s)`、`0 Error(s)`
|
||||
- 本轮已验证 `dotnet test GFramework.Godot.Tests/GFramework.Godot.Tests.csproj -c Release --filter "FullyQualifiedName~AbstractArchitectureModuleInstallationTests|FullyQualifiedName~GodotYamlConfigLoaderTests|FullyQualifiedName~RichTextMarkupTests"`,结果为 `Passed: 15`
|
||||
- `GFramework.Godot` 原先暴露的 `MA0051` 与 `MA0004` 热点都已清理完成;当前同域低风险切片基本耗尽
|
||||
|
||||
## 当前风险
|
||||
|
||||
- 如果后续继续依赖增量 `dotnet build`,容易再次把 warning 数量误判为 0
|
||||
- 缓解措施:每轮 warning 检查前先执行 `dotnet clean`,再执行目标 `dotnet build`
|
||||
- 仓库根目录 `dotnet clean` 目前仍然无法给出新的 clean 基线
|
||||
- 缓解措施:若下一轮继续做整仓 warning reduction,先定位 `dotnet clean` 的 solution-level 失败原因,或明确继续沿用用户确认的 `1193 warning(s)` clean 基线与本轮 `1184 warning(s)` direct build 观测值
|
||||
- 当前 worktree 已存在与本批次无关的未提交改动
|
||||
- 缓解措施:提交当前批次时只暂存 `GFramework.Godot.SourceGenerators.Tests` 与对应 `ai-plan` 文件,避免混入其他 topic 变更
|
||||
- `GFramework.Game` 当前 `Release` build 仍带有既有 analyzer warning 基线
|
||||
- 缓解措施:本轮仅验证改动未新增 `UnifiedSettingsDataRepository` / `UnifiedSettingsFile` 相关 warning;若继续在该模块做 warning reduction,需要另开切片处理现存基线
|
||||
- 缓解措施:若下一轮继续做整仓 warning reduction,先定位 `dotnet clean` 的 solution-level 失败原因,或明确继续沿用用户确认的 `1193 warning(s)` clean 基线与本轮 `1122 warning(s)` direct build 观测值
|
||||
- 当前 worktree 仍存在未跟踪的 `.codex` 目录
|
||||
- 缓解措施:提交当前批次时只暂存 analyzer-warning-reduction 相关源码与 `ai-plan` 文件,避免把工作目录辅助文件混入提交
|
||||
- 下一轮最明显的剩余热点将转入 `GFramework.Game` 等高 warning 基线模块
|
||||
- 缓解措施:恢复时先重新跑整仓 build 热点筛选,再决定是否接受更高上下文成本的 `GFramework.Game` 切片,或先排查 solution-level clean 失败原因
|
||||
|
||||
## 活跃文档
|
||||
|
||||
@ -51,25 +49,19 @@
|
||||
|
||||
## 验证说明
|
||||
|
||||
- `dotnet clean`
|
||||
- `dotnet clean GFramework.sln -c Release`
|
||||
- 结果:失败;停在 solution `ValidateSolutionConfiguration`,`0 Warning(s)`、`0 Error(s)`,未输出更具体的 error 文本
|
||||
- `dotnet build`
|
||||
- 结果:成功;`1184 Warning(s)`、`0 Error(s)`
|
||||
- `dotnet build GFramework.Godot.SourceGenerators.Tests/GFramework.Godot.SourceGenerators.Tests.csproj`
|
||||
- 初始结果:成功;`24 Warning(s)`、`0 Error(s)`
|
||||
- 本轮收尾结果:成功;`0 Warning(s)`、`0 Error(s)`
|
||||
- `dotnet build GFramework.Godot.SourceGenerators.Tests/GFramework.Godot.SourceGenerators.Tests.csproj -c Release`
|
||||
- `dotnet build GFramework.sln -c Release`
|
||||
- 结果:成功;`1122 Warning(s)`、`0 Error(s)`
|
||||
- `dotnet build GFramework.Godot/GFramework.Godot.csproj -c Release`
|
||||
- 结果:成功;`0 Warning(s)`、`0 Error(s)`
|
||||
- `dotnet test GFramework.Godot.SourceGenerators.Tests/GFramework.Godot.SourceGenerators.Tests.csproj -c Release --no-build`
|
||||
- 结果:成功;`Passed: 48`、`Failed: 0`
|
||||
- `dotnet build GFramework.Game/GFramework.Game.csproj -c Release`
|
||||
- 结果:成功;`533 Warning(s)`、`0 Error(s)`;模块仍存在既有 warning 基线,本轮 follow-up 仅处理 PR review 指向的 comparer 契约与测试异步等待一致性
|
||||
- `dotnet build GFramework.Godot.SourceGenerators.Tests/GFramework.Godot.SourceGenerators.Tests.csproj -c Release`
|
||||
- 结果:成功;`0 Warning(s)`、`0 Error(s)`
|
||||
- `dotnet test GFramework.Godot.SourceGenerators.Tests/GFramework.Godot.SourceGenerators.Tests.csproj -c Release --no-build`
|
||||
- 结果:成功;`Passed: 48`、`Failed: 0`
|
||||
- `dotnet test GFramework.Godot.Tests/GFramework.Godot.Tests.csproj -c Release --filter "FullyQualifiedName~AbstractArchitectureModuleInstallationTests|FullyQualifiedName~GodotYamlConfigLoaderTests|FullyQualifiedName~RichTextMarkupTests"`
|
||||
- 结果:成功;`Passed: 15`、`Failed: 0`
|
||||
- `dotnet build GFramework.Godot.Tests/GFramework.Godot.Tests.csproj -c Release`
|
||||
- 首次并行验证:成功;`1 Warning(s)`、`0 Error(s)`;`MSB3026` 来自与并行 `dotnet test` 竞争同一输出 DLL
|
||||
- 串行复验:成功;`0 Warning(s)`、`0 Error(s)`
|
||||
|
||||
## 下一步建议
|
||||
|
||||
1. 提交当前 comparer 契约与 `ConfigureAwait(false)` PR follow-up,并确认只纳入本 topic 相关文件
|
||||
2. 视 PR review 反馈决定是否继续收敛 `GFramework.Game` 现有 warning 基线,或返回下一轮整仓 warning 热点筛选
|
||||
1. 提交当前 `GFramework.Godot` / `GFramework.Godot.Tests` warning 清理批次,并继续保持只纳入本 topic 相关文件
|
||||
2. 下一轮若继续使用 `$gframework-batch-boot 75`,先决定是优先排查 solution-level `dotnet clean` 失败,还是接受更高上下文成本进入 `GFramework.Game` warning 热点
|
||||
|
||||
@ -2,6 +2,37 @@
|
||||
|
||||
# Analyzer Warning Reduction 追踪
|
||||
|
||||
## 2026-04-24 — RP-053
|
||||
|
||||
### 阶段:`GFramework.Godot` / `GFramework.Godot.Tests` 小批次 warning 清理
|
||||
|
||||
- 触发背景:
|
||||
- 用户以 `$gframework-batch-boot 75` 要求继续按批次推进 analyzer warning reduction,并以 `origin/main` 作为累计分支 diff 基线
|
||||
- 当前 worktree `fix/analyzer-warning-reduction-batch` 相对 `origin/main` 的已提交分支 diff 为 `0` 个文件,具备继续落一个低风险 warning batch 的空间
|
||||
- solution-level `dotnet clean GFramework.sln -c Release` 仍在 `ValidateSolutionConfiguration` 阶段失败,因此本轮继续用直接 `dotnet build GFramework.sln -c Release` 建立热点观察值
|
||||
- 主线程实施:
|
||||
- 运行 `dotnet build GFramework.sln -c Release`,确认当前整仓观测值为 `1122 warning(s)`,并从输出中挑选 `GFramework.Godot` 的小范围热点作为本轮批次
|
||||
- 在 `GodotYamlConfigEnvironment.cs` 中按“普通文件系统 / Godot 路径”拆分目录枚举 helper,消除 `MA0051`
|
||||
- 在 `AbstractArchitecture.cs` 与 `SceneBehaviorBase.cs` 中将必须保留 Godot 主线程上下文的 await 显式改为 `.ConfigureAwait(true)`,清理 `MA0004` 并把线程意图写入注释
|
||||
- 在 `GFramework.Godot.Tests` 中补齐异步断言的 `.ConfigureAwait(false)`,并让 `RichTextMarkupTests` 的测试字典显式指定 `StringComparer.Ordinal`
|
||||
- 验证里程碑:
|
||||
- `dotnet clean GFramework.sln -c Release`
|
||||
- 结果:失败;停在 `ValidateSolutionConfiguration`,`0 Warning(s)`、`0 Error(s)`
|
||||
- `dotnet build GFramework.sln -c Release`
|
||||
- 结果:成功;`1122 Warning(s)`、`0 Error(s)`
|
||||
- `dotnet build GFramework.Godot/GFramework.Godot.csproj -c Release`
|
||||
- 第一轮修复后:成功;`12 Warning(s)`、`0 Error(s)`,仅剩 `MA0004`
|
||||
- 第二轮修复后:成功;`0 Warning(s)`、`0 Error(s)`
|
||||
- `dotnet test GFramework.Godot.Tests/GFramework.Godot.Tests.csproj -c Release --filter "FullyQualifiedName~AbstractArchitectureModuleInstallationTests|FullyQualifiedName~GodotYamlConfigLoaderTests|FullyQualifiedName~RichTextMarkupTests"`
|
||||
- 结果:成功;`Passed: 15`、`Failed: 0`
|
||||
- `dotnet build GFramework.Godot.Tests/GFramework.Godot.Tests.csproj -c Release`
|
||||
- 并行验证时:成功;`1 Warning(s)`、`0 Error(s)`;`MSB3026` 为与并行 `dotnet test` 竞争输出 DLL 的文件占用
|
||||
- 串行复验:成功;`0 Warning(s)`、`0 Error(s)`
|
||||
- 当前结论:
|
||||
- `GFramework.Godot` 与 `GFramework.Godot.Tests` 本轮直接涉及的 warning 已全部清零
|
||||
- 当前待提交代码批次相对 `origin/main` 的源码 diff 为 `6` 个文件、`107` 行,距离 `$gframework-batch-boot 75` 主停止阈值仍有充足余量
|
||||
- 继续推进的下一批候选将主要落在 `GFramework.Game` 等高 warning 基线模块,已不再属于当前同等级低风险切片,因此本轮在这里收口并进入提交
|
||||
|
||||
## 2026-04-24 — RP-052
|
||||
|
||||
### 阶段:PR review follow-up(comparer 契约 + `ConfigureAwait(false)` 收尾)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user