Add MSBuild log analyzer to CI workflows#932
Open
jasonleenaylor wants to merge 2 commits into
Open
Conversation
Replace the simple grep-based "Scan Build Output" step in both patch-installer-cd.yml and base-installer-cd.yml with a Python analyzer that streams the build log, identifies root-cause failures with context, and surfaces them directly in the GitHub Actions job summary via GITHUB_STEP_SUMMARY and ::error:: annotations. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The break on reaching _MAX_ERRORS_DETAIL only exited the inner loop, so subsequent failed steps would each print a header and duplicate truncation message. Now the outer loop also breaks at the limit and the truncation message is printed once after both loops. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds a Python-based MSBuild log analyzer to CI so workflow runs surface actionable build-failure summaries and annotations directly in the GitHub Actions UI, replacing the prior grep-based error scan.
Changes:
- Added
scripts/tools/analyze_build_log.pyto parse MSBuild logs, generate a$GITHUB_STEP_SUMMARYreport, and emit::errorannotations. - Added
scripts/tools/build_error_enrichments.pyto enrich known build failures (currently WiX PYRO0305) with root-cause context via on-disk lookups. - Updated patch/base installer CD workflows to run the analyzer step (with
if: always()).
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
scripts/tools/build_error_enrichments.py |
Adds enrichment registry + WiX PYRO0305 root-cause lookup helpers. |
scripts/tools/analyze_build_log.py |
Implements streaming MSBuild log parsing + job summary markdown + annotations emission. |
.github/workflows/patch-installer-cd.yml |
Replaces grep scan step with analyzer invocation. |
.github/workflows/base-installer-cd.yml |
Replaces grep scan step with analyzer invocation. |
Comment on lines
+346
to
+351
| # Root cause | ||
| root = failed_steps[0] | ||
| w("### Root Cause") | ||
| w(f"**First failed step:** [{steps.index(root) + 1}] `{root.name}` at line {root.first_failure_line:,}") | ||
| if len(failed_steps) > 1: | ||
| w(f"\n{len(failed_steps) - 1} subsequent step(s) also failed (likely cascading).") |
Comment on lines
+416
to
+433
| def emit_github_annotations(steps: list[StepRecord], enrichment_findings: list, workspace: Optional[Path] = None) -> None: | ||
| """Emit ::error:: workflow commands for GitHub annotation badges.""" | ||
| count = 0 | ||
| for step in steps: | ||
| if not step.failed: | ||
| continue | ||
| for err in step.errors: | ||
| if count >= _MAX_ANNOTATIONS: | ||
| return | ||
| diag = MSBUILD_DIAGNOSTIC_RX.match(err.message) | ||
| if diag: | ||
| source = _strip_workspace(diag.group("source"), workspace) | ||
| code = diag.group("code") | ||
| msg = diag.group("message") | ||
| print(f"::error file={source}::{code}: {msg}") | ||
| else: | ||
| print(f"::error ::{err.message[:200]}") | ||
| count += 1 |
Comment on lines
+235
to
+239
| - name: Analyze Build Log | ||
| if: always() && steps.build.outcome != 'skipped' | ||
| shell: pwsh | ||
| run: | | ||
| $results = Select-String -Path "build.log" -Pattern "^\s*[1-9][0-9]* Error\(s\)" | ||
| if ($results) { | ||
| foreach ($result in $results) { | ||
| Write-Host "Found errors in build.log $($result.LineNumber): $($result.Line)" -ForegroundColor red | ||
| } | ||
| exit 1 | ||
| } else { | ||
| Write-Host "No errors found" -ForegroundColor green | ||
| exit 0 | ||
| } | ||
| python scripts/tools/analyze_build_log.py build.log --workspace "${{ github.workspace }}" |
Comment on lines
+166
to
+170
| - name: Analyze Build Log | ||
| if: always() && steps.build.outcome != 'skipped' | ||
| shell: pwsh | ||
| run: | | ||
| $results = Select-String -Path "build.log" -Pattern "^\s*[1-9][0-9]* Error\(s\)" | ||
| if ($results) { | ||
| foreach ($result in $results) { | ||
| Write-Host "Found errors in build.log $($result.LineNumber): $($result.Line)" -ForegroundColor red | ||
| } | ||
| exit 1 | ||
| } else { | ||
| Write-Host "No errors found" -ForegroundColor green | ||
| exit 0 | ||
| } | ||
| python scripts/tools/analyze_build_log.py build.log --workspace "${{ github.workspace }}" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
scripts/tools/analyze_build_log.pyandscripts/tools/build_error_enrichments.py— a Python log analyzer that streams MSBuild logs in a single pass to identify root-cause build failurespatch-installer-cd.ymlandbase-installer-cd.ymlwith the new analyzer$GITHUB_STEP_SUMMARY(markdown with step table, root cause, collapsible context) and::error::annotationsMotivation
When builds fail, the old "Scan Build Output" step only checked for
N Error(s)summary lines — it didn't show which project failed, the actual error messages, or surrounding context. Diagnosing failures required downloading the (often 1GB+) build log artifact and running a local analysis script.What changed
scripts/tools/analyze_build_log.py— single-pass streaming parser for MSBuild logs, produces GitHub job summary markdown and error annotationsscripts/tools/build_error_enrichments.py— extensible registry of known error patterns (currently WiX PYRO0305) with on-disk file lookups for root-cause enrichment.github/workflows/patch-installer-cd.yml— "Scan Build Output" → "Analyze Build Log" withif: always()so it runs even when the build fails.github/workflows/base-installer-cd.yml— same changeTest plan
🤖 Generated with Claude Code
This change is