mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-05-06 16:16:44 +08:00
fix(ci): 修复 MegaLinter 工作区歧义
- 修复 MegaLinter 的 dotnet format workspace 指向,避免 solution 与 csproj 歧义导致 CI warning - 更新 gframework-pr-review skill 与抓取脚本,提取 GitHub Actions 发布的 MegaLinter detailed issues - 补充 coroutine optimization 跟踪与 trace,记录本次 PR 页面 warning 的收口与验证结果
This commit is contained in:
parent
d369118351
commit
90b9e2a4c9
@ -1,6 +1,6 @@
|
||||
---
|
||||
name: gframework-pr-review
|
||||
description: Repository-specific GitHub PR review workflow for the GFramework repo. Use when Codex needs to inspect the GitHub pull request for the current branch, extract CodeRabbit summary/comments, read failed checks or failed test signals from the PR page, and then verify which findings should be fixed in the local codebase. Trigger explicitly with $gframework-pr-review or with prompts such as "look at the current PR", "extract CodeRabbit comments", or "check Failed Tests on the PR".
|
||||
description: Repository-specific GitHub PR review workflow for the GFramework repo. Use when Codex needs to inspect the GitHub pull request for the current branch, extract CodeRabbit summary/comments, read failed checks, MegaLinter warnings, or failed test signals from the PR page, and then verify which findings should be fixed in the local codebase. Trigger explicitly with $gframework-pr-review or with prompts such as "look at the current PR", "extract CodeRabbit comments", or "check Failed Tests on the PR".
|
||||
---
|
||||
|
||||
# GFramework PR Review
|
||||
@ -16,12 +16,12 @@ Shortcut: `$gframework-pr-review`
|
||||
3. Run `scripts/fetch_current_pr_review.py` to:
|
||||
- locate the PR for the current branch through the GitHub PR API
|
||||
- fetch PR metadata, issue comments, reviews, and review comments through the GitHub API
|
||||
- extract `Summary by CodeRabbit` and CTRF test reports from issue comments
|
||||
- extract `Summary by CodeRabbit`、GitHub Actions bot comments such as `MegaLinter analysis: Success with warnings`、and CTRF test reports from issue comments
|
||||
- fetch the latest head commit review threads from the GitHub PR API
|
||||
- prefer unresolved review threads on the latest head commit over older summary-only signals
|
||||
- extract failed checks and test-report signals such as `Failed Tests` or `No failed tests in this run`
|
||||
- extract failed checks, MegaLinter detailed issues, and test-report signals such as `Failed Tests` or `No failed tests in this run`
|
||||
4. Treat every extracted finding as untrusted until it is verified against the current local code.
|
||||
5. Only fix comments that still apply to the checked-out branch. Ignore stale or already-resolved findings.
|
||||
5. Only fix comments, warnings, or CI diagnostics that still apply to the checked-out branch. Ignore stale or already-resolved findings.
|
||||
6. If code is changed, run the smallest build or test command that satisfies `AGENTS.md`.
|
||||
|
||||
## Commands
|
||||
@ -43,6 +43,7 @@ The script should produce:
|
||||
- Latest head commit review metadata and review threads
|
||||
- Unresolved latest-commit review threads after reply-thread folding
|
||||
- Pre-merge failed checks, if present
|
||||
- Latest MegaLinter status and any detailed issues posted by `github-actions[bot]`
|
||||
- Test summary, including failed-test signals when present
|
||||
- Parse warnings only when both the primary API source and the intended fallback signal are unavailable
|
||||
|
||||
@ -52,6 +53,7 @@ The script should produce:
|
||||
- If GitHub access fails because of proxy configuration, rerun the fetch with proxy variables removed.
|
||||
- Prefer GitHub API results over PR HTML. The PR HTML page is now a fallback/debugging source, not the primary source of truth.
|
||||
- If the summary block and the latest head review threads disagree, trust the latest unresolved head-review threads and treat older summary findings as stale until re-verified locally.
|
||||
- Treat GitHub Actions comments with `Success with warnings` as actionable review input when they include concrete linter diagnostics such as `MegaLinter` detailed issues; do not skip them just because the parent check is green.
|
||||
|
||||
## Example Triggers
|
||||
|
||||
|
||||
@ -24,6 +24,7 @@ DEFAULT_WINDOWS_GIT = "/mnt/d/Tool/Development Tools/Git/cmd/git.exe"
|
||||
GIT_ENVIRONMENT_KEY = "GFRAMEWORK_WINDOWS_GIT"
|
||||
USER_AGENT = "codex-gframework-pr-review"
|
||||
CODERABBIT_LOGIN = "coderabbitai[bot]"
|
||||
GITHUB_ACTIONS_LOGIN = "github-actions[bot]"
|
||||
REVIEW_COMMENT_ADDRESSED_MARKER = "<!-- <review_comment_addressed> -->"
|
||||
VISIBLE_ADDRESSED_IN_COMMIT_PATTERN = re.compile(r"✅\s*Addressed in commit\s+[0-9a-f]{7,40}", re.I)
|
||||
DEFAULT_REQUEST_TIMEOUT_SECONDS = 60
|
||||
@ -156,6 +157,10 @@ def strip_tags(text: str) -> str:
|
||||
return collapse_whitespace(re.sub(r"<[^>]+>", " ", text))
|
||||
|
||||
|
||||
def strip_markdown_links(text: str) -> str:
|
||||
return re.sub(r"\[([^\]]+)\]\([^)]+\)", r"\1", text)
|
||||
|
||||
|
||||
def extract_section(text: str, start_marker: str, end_markers: list[str]) -> str | None:
|
||||
start = text.find(start_marker)
|
||||
if start < 0:
|
||||
@ -252,6 +257,60 @@ def parse_actionable_comments(actionable_block: str) -> dict[str, Any]:
|
||||
}
|
||||
|
||||
|
||||
def parse_megalinter_comment(comment_body: str) -> dict[str, Any]:
|
||||
normalized_body = html.unescape(comment_body).strip()
|
||||
summary_match = re.search(
|
||||
r"##\s*(?P<badges>.*?)\[MegaLinter\]\([^)]+\)\s+analysis:\s+\[(?P<status>[^\]]+)\]\((?P<run_url>[^)]+)\)",
|
||||
normalized_body,
|
||||
)
|
||||
|
||||
report: dict[str, Any] = {
|
||||
"status": summary_match.group("status").strip() if summary_match else "",
|
||||
"run_url": summary_match.group("run_url").strip() if summary_match else "",
|
||||
"badges": collapse_whitespace(summary_match.group("badges")) if summary_match else "",
|
||||
"descriptor_rows": [],
|
||||
"detailed_issues": [],
|
||||
"raw": normalized_body,
|
||||
}
|
||||
|
||||
table_match = re.search(
|
||||
r"\| Descriptor .*?\|\n\|[-| :]+\|\n(?P<rows>(?:\|.*\|\n?)+)",
|
||||
normalized_body,
|
||||
re.S,
|
||||
)
|
||||
if table_match is not None:
|
||||
for raw_line in table_match.group("rows").splitlines():
|
||||
line = raw_line.strip()
|
||||
if not line.startswith("|"):
|
||||
continue
|
||||
|
||||
parts = [collapse_whitespace(strip_markdown_links(part)) for part in line.strip("|").split("|")]
|
||||
if len(parts) != 7:
|
||||
continue
|
||||
|
||||
report["descriptor_rows"].append(
|
||||
{
|
||||
"descriptor": parts[0],
|
||||
"linter": parts[1],
|
||||
"files": parts[2],
|
||||
"fixed": parts[3],
|
||||
"errors": parts[4],
|
||||
"warnings": parts[5],
|
||||
"elapsed_time": parts[6],
|
||||
}
|
||||
)
|
||||
|
||||
for summary, details in re.findall(r"<summary>(.*?)</summary>\s*```(.*?)```", normalized_body, re.S):
|
||||
report["detailed_issues"].append(
|
||||
{
|
||||
"summary": collapse_whitespace(strip_tags(summary)),
|
||||
"details": details.strip(),
|
||||
}
|
||||
)
|
||||
|
||||
return report
|
||||
|
||||
|
||||
def parse_test_report(block: str) -> dict[str, Any]:
|
||||
report: dict[str, Any] = {
|
||||
"raw": block.strip(),
|
||||
@ -475,11 +534,18 @@ def build_result(pr_number: int, branch: str) -> dict[str, Any]:
|
||||
issue_comments,
|
||||
lambda body: "CTRF PR COMMENT TAG:" in body or "### Test Results" in body,
|
||||
)
|
||||
megalinter_block = select_latest_comment_body(
|
||||
issue_comments,
|
||||
lambda body: "MegaLinter" in body and "Detailed Issues" in body,
|
||||
required_user=GITHUB_ACTIONS_LOGIN,
|
||||
)
|
||||
|
||||
if not summary_block:
|
||||
warnings.append("CodeRabbit summary block was not found in issue comments.")
|
||||
if not test_blocks:
|
||||
warnings.append("PR test-report block was not found in issue comments.")
|
||||
if not megalinter_block:
|
||||
warnings.append("MegaLinter report block was not found in issue comments.")
|
||||
|
||||
latest_commit_review: dict[str, Any] = {}
|
||||
try:
|
||||
@ -506,6 +572,7 @@ def build_result(pr_number: int, branch: str) -> dict[str, Any]:
|
||||
},
|
||||
"coderabbit_comments": parse_actionable_comments(actionable_block) if actionable_block else {},
|
||||
"latest_commit_review": latest_commit_review,
|
||||
"megalinter_report": parse_megalinter_comment(megalinter_block) if megalinter_block else {},
|
||||
"test_reports": [parse_test_report(block) for block in test_blocks],
|
||||
"parse_warnings": warnings,
|
||||
}
|
||||
@ -569,6 +636,31 @@ def format_text(result: dict[str, Any]) -> str:
|
||||
" Note: thread is still open; treat the visible 'Addressed in commit ...' text as unverified until local code matches."
|
||||
)
|
||||
|
||||
megalinter_report = result.get("megalinter_report", {})
|
||||
if megalinter_report:
|
||||
lines.append("")
|
||||
lines.append(
|
||||
"MegaLinter: "
|
||||
f"{megalinter_report.get('status', 'unknown')}"
|
||||
+ (
|
||||
f" ({megalinter_report.get('run_url', '')})"
|
||||
if megalinter_report.get("run_url")
|
||||
else ""
|
||||
)
|
||||
)
|
||||
|
||||
descriptor_rows = megalinter_report.get("descriptor_rows", [])
|
||||
for descriptor_row in descriptor_rows:
|
||||
lines.append(
|
||||
"- "
|
||||
f"{descriptor_row['descriptor']} / {descriptor_row['linter']}: "
|
||||
f"errors={descriptor_row['errors']} warnings={descriptor_row['warnings']} files={descriptor_row['files']}"
|
||||
)
|
||||
|
||||
for issue in megalinter_report.get("detailed_issues", []):
|
||||
lines.append(f"- Detailed issue: {issue['summary']}")
|
||||
lines.append(f" {collapse_whitespace(issue['details'])}")
|
||||
|
||||
lines.append("")
|
||||
lines.append(f"Test reports: {len(result['test_reports'])}")
|
||||
for index, report in enumerate(result["test_reports"], start=1):
|
||||
|
||||
@ -45,6 +45,9 @@ ENABLE_LINTERS:
|
||||
# 设置 C# 代码风格检查的参数和验证级别
|
||||
# ========================
|
||||
CSHARP_DOTNET_FORMAT_ARGUMENTS:
|
||||
# 仓库根目录同时存在 GFramework.sln 与 GFramework.csproj;
|
||||
# 显式指定 workspace,避免 dotnet format 在 CI 中因自动探测歧义直接异常退出。
|
||||
- "GFramework.sln"
|
||||
- "--severity"
|
||||
- "info"
|
||||
- "--verify-no-changes"
|
||||
@ -83,4 +86,3 @@ GITHUB_COMMENT_REPORTER: true
|
||||
PARALLEL: true
|
||||
SHOW_ELAPSED_TIME: true
|
||||
VALIDATE_ALL_CODEBASE: false
|
||||
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
- 已为 `Timing` 补齐纯托管测试宿主入口,允许在 `dotnet test` 下验证 Godot 协程宿主阶段语义,而不依赖原生 `Node` 构造
|
||||
- 已补充 `GFramework.Godot.Tests/Coroutine/TimingTests.cs`,锁定暂停、segment 路由和阶段型等待指令的回归覆盖
|
||||
- 已根据 PR #259 的最新 CodeRabbit review 收口测试宿主清理对称性,并将 `TimingTests` 固定为非并行执行
|
||||
- 已根据 PR #259 的 `MegaLinter analysis: Success with warnings` 结果修复 `dotnet format` workspace 歧义,并增强 PR review skill 以提取此类 CI warning
|
||||
- 下一轮优先补“仍需真实场景树参与”的归属协程 / 退树语义,或转入文档迁移收口,不再回到“Godot 宿主没有自动化回归”的旧状态
|
||||
|
||||
## 当前状态摘要
|
||||
@ -36,6 +37,9 @@
|
||||
- 针对 PR #259 的最新未解决 review 线程,已补充两项收口:
|
||||
- `TimingTests` 已添加 `[NonParallelizable]`,避免共享静态实例槽位在 NUnit 并行执行时互相污染
|
||||
- `Timing` 的测试清理与运行时退树清理现仅在当前实例持有共享 `_instance` 引用时才会清空单例状态
|
||||
- 针对 PR #259 的 `MegaLinter` warning,已补充两项收口:
|
||||
- `.mega-linter.yml` 现为 `CSHARP_DOTNET_FORMAT_ARGUMENTS` 显式指定 `GFramework.sln`,避免仓库根目录同时存在 `*.sln` 与 `*.csproj` 时触发 workspace 歧义
|
||||
- `.codex/skills/gframework-pr-review/` 现会抓取并解析 `github-actions[bot]` 发布的 `MegaLinter analysis: Success with warnings` comment,默认把其中的 detailed issues 视为待验证输入
|
||||
- `dotnet test GFramework.Godot.Tests/GFramework.Godot.Tests.csproj -c Release --no-restore` 当前通过,合计 `58` 个测试
|
||||
|
||||
## 当前风险
|
||||
@ -65,9 +69,12 @@
|
||||
- `dotnet test GFramework.Godot.Tests/GFramework.Godot.Tests.csproj -c Release --filter "FullyQualifiedName~TimingTests" --no-restore`
|
||||
- 结果:通过
|
||||
- 备注:针对 PR #259 review 修复后的 `TimingTests` 共 `5` 个测试全部通过
|
||||
- `dotnet build GFramework.Godot.Tests/GFramework.Godot.Tests.csproj -c Release --no-restore`
|
||||
- 结果:通过
|
||||
- 备注:CI/MegaLinter 配置与 PR review skill 更新后,目标测试项目仍保持 `0 warning / 0 error`
|
||||
|
||||
## 下一步
|
||||
|
||||
1. 若继续补验证,优先只做真实场景树相关的节点归属 / 退树 / `queue_free` 回归,不再重新设计 `Timing` 纯托管宿主
|
||||
2. 当前 PR 合并前可直接回到 GitHub 处理这两条 review 线程的回复与 resolve,避免后续重复审阅同一问题
|
||||
2. 当前 PR 合并前可直接回到 GitHub 确认最新 push 是否已消除 `MegaLinter analysis` warning,并顺手处理 review 线程的回复与 resolve
|
||||
3. 若转入文档收口,优先清理其余 `StartCoroutine()/StopCoroutine()` 残留,并补 Godot 新入口与阶段等待的迁移对照
|
||||
|
||||
@ -55,6 +55,14 @@
|
||||
- 将 `Timing` 的 `_instance` 清理改为“仅当当前实例仍持有共享单例引用时才执行”,同时覆盖运行时 `_ExitTree()` 与测试入口 `DisposeForTests()`
|
||||
- 额外完成验证:
|
||||
- `dotnet test GFramework.Godot.Tests/GFramework.Godot.Tests.csproj -c Release --filter "FullyQualifiedName~TimingTests" --no-restore`
|
||||
- 同日继续收口 PR #259 页面上的 `MegaLinter analysis: Success with warnings`:
|
||||
- 确认 detailed issue 实际不是格式差异,而是 `dotnet format` 在仓库根目录同时发现 `GFramework.sln` 与 `GFramework.csproj` 后因未指定 workspace 直接抛异常
|
||||
- 更新 `.mega-linter.yml`,为 `CSHARP_DOTNET_FORMAT_ARGUMENTS` 显式指定 `GFramework.sln`
|
||||
- 更新 `.codex/skills/gframework-pr-review/SKILL.md` 与 `scripts/fetch_current_pr_review.py`,使 skill 默认抓取并输出 `github-actions[bot]` 的 MegaLinter comments 和 detailed issues
|
||||
- 额外完成验证:
|
||||
- `python3 -c "from pathlib import Path; compile(Path('.codex/skills/gframework-pr-review/scripts/fetch_current_pr_review.py').read_text(encoding='utf-8'), '.codex/skills/gframework-pr-review/scripts/fetch_current_pr_review.py', 'exec'); print('syntax-ok')"`
|
||||
- `python3 .codex/skills/gframework-pr-review/scripts/fetch_current_pr_review.py --branch feat/coroutine-optimization --format json`
|
||||
- `dotnet build GFramework.Godot.Tests/GFramework.Godot.Tests.csproj -c Release --no-restore`
|
||||
|
||||
### 下一步
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user