Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 8, 2025

Fixes #10592

Context

MSBuild diagnostics are not formatted for CI/CD provider displays. Errors and warnings appear as plain text, missing provider-specific markup for collapsible sections, annotations, and workflow commands.

Changes Made

Logger Implementation

  • Added GitHubActionsLogger extending ProjectTrackingLoggerBase with workflow commands (::error, ::warning, ::group)
  • Added AzureDevOpsLogger extending ProjectTrackingLoggerBase with Azure Pipelines logging commands (##vso[task.logissue], ##[group])
  • Added GitLabLogger extending ProjectTrackingLoggerBase with ANSI color codes and collapsible sections
  • Each logger implements distributed logger pattern with corresponding forwarding logger for multi-process builds
  • Loggers are located in src/Build/Logging/CICDLogger/ and included in Microsoft.Build.csproj for API accessibility
  • Namespaces use Microsoft.Build.Logging.CICDLogger.* pattern for public API access

Project Tracking

  • All three loggers extend ProjectTrackingLoggerBase to aggregate project data:
    • Extracts target framework and runtime identifier from evaluation
    • Buffers diagnostics (errors, warnings, messages) per project with timestamp tracking
    • Emits grouped output with context at project completion (e.g., "Building MyProject.csproj (net8.0 | linux-x64) - 2 error(s), 5 warning(s)")
    • Events are output in chronological order using timestamp-based sorting
  • Implements proper either-or logic for messages: buffers for project context OR writes immediately, never both
  • Azure DevOps uses collapsible ##[group] instead of ##[section] for better UX
  • Consolidated diagnostic formatting: single WriteDiagnostic method replaces separate WriteError/WriteWarning methods across all three loggers
  • GitLab logger only colorizes diagnostic type (ERROR/WARNING) for better legibility, keeping file paths, codes, and messages in default color

GitHub Actions Enhancements

  • Supports ACTIONS_STEP_DEBUG environment variable to force diagnostic verbosity
  • Generates build summary in GITHUB_STEP_SUMMARY file with:
    • Overall build status with emojis (✅/❌)
    • Total error and warning counts
    • Per-project details with target framework and runtime identifier
    • Collapsible diagnostics sections with timestamp-ordered events
    • Markdown-formatted output with proper styling

Auto-Detection

  • Modified XMake.cs to detect CI/CD environments via environment variables (GITHUB_ACTIONS, TF_BUILD, GITLAB_CI)
  • Added TryProcessCICDLogger to auto-select provider logger when no explicit console/terminal logger specified
  • Integrates into existing logger selection flow between terminal and console logger

Code Quality

  • All new files use #nullable enable
  • Follows MSBuild performance patterns (minimal allocations, StringBuilder usage)

Testing

CI/CD Logger Tests
Added comprehensive unit tests for each provider:

  • Environment detection tests
  • Diagnostic formatting tests (errors, warnings, messages)
  • Project lifecycle tests (buffering, grouping)
  • Special character escaping tests

Test Suite Compatibility
Updated existing tests to explicitly use ConsoleLogger to prevent CI/CD logger auto-detection in CI environments:

  • Modified XMake_Tests.ExecuteMSBuildExe to add -logger:ConsoleLogger
  • Added ExecMSBuildWithConsoleLogger helper in MSBuildServer_Tests and updated all invocations
  • Updated PerfLog_Tests to explicitly specify ConsoleLogger
  • Added ExecBootstrapedMSBuildWithConsoleLogger helper in EndToEndTests and updated all test methods

These changes ensure tests use the expected ConsoleLogger instead of auto-detecting CI/CD loggers when environment variables like TF_BUILD are present in CI pipelines.

Notes

All three loggers are part of the Microsoft.Build assembly and accessible through the MSBuild APIs, not exclusive to the MSBuild command-line tool. This allows library consumers to use these loggers programmatically. The loggers use the ProjectTrackingLoggerBase infrastructure for consistent project tracking and rich diagnostic output across all CI/CD providers. Events are tracked with timestamps and output in chronological order to maintain accurate build sequencing.

Original prompt

This section details on the original issue you should resolve

<issue_title>Enhance the MSBuild output experience for CI/CD providers</issue_title>
<issue_description>### Summary

MSBuild today doesn't nicely integrate into CI/CD providers, so diagnostics from the build are not reported in a way that providers can easily integrate into their summaries/displays. We should create provider-specific loggers and detections that auto-enable those providers in lieu of any explicit ConsoleLogger or TerminalLogger specification by the user.

Background and Motivation

This is a relatively simple way to enhance the user experience of MSBuild that is straightforward to accomplish.

Proposed Feature

We should create new loggers for

  • GitHub Actions
  • Azure DevOps
  • GitLab
  • Other user-suggested providers

To reduce the duplication of those loggers, we should build these as different 'formatters' on top of the better logical model that #12587 introduces.

Each of these loggers should

  • expose a detection criteria for if that logger should be used that's based on the environment variables described by that CI/CD provider in their documentation
  • use the provider-specific mechanisms for communicating diagnostics, source files and locations, and additional data as described by the CI/CD provider in their documentation
  • be a 'distributed logger' in MSBuild parlance so that we can filter events from worker nodes that are sent to the central node
  • if the CI/CD provider supports reporting 'progress' then the per-node information exposed by separate the tracking parts of TL into a reusable base, so that TL becomes a 'renderer' #12587 can be used to drive that experience

When MSBuild's command line is processing the Logger configuration to use, if neither console logger nor terminal logger have been explicitly specified then the available CI/CD provider-specific loggers are checked to see if any are applicable to the current execution environment. If there is one and only one match, that logger should be used instead of the console or terminal logger.

Alternative Designs

No response</issue_description>

<agent_instructions>Start by implementing these loggers for GitHub Actions, Azure DevOps, and GitLab CI/CD providers</agent_instructions>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI self-assigned this Nov 8, 2025
Copilot AI and others added 2 commits November 8, 2025 16:11
… and GitLab

Co-authored-by: baronfel <573979+baronfel@users.noreply.github.com>
…sive tests, refactor Azure DevOps logger to use ProjectTrackingLoggerBase

Co-authored-by: baronfel <573979+baronfel@users.noreply.github.com>
Copilot AI changed the title [WIP] Enhance MSBuild output experience for CI/CD providers Add CI/CD provider-specific loggers for GitHub Actions, Azure DevOps, and GitLab Nov 8, 2025
Copilot AI requested a review from baronfel November 8, 2025 16:33
Copilot finished work on behalf of baronfel November 8, 2025 16:33
@baronfel
Copy link
Member

baronfel commented Nov 8, 2025

@copilot src/MSBuild/CICDLogger/AzureDevOps/AzureDevOpsLogger.cs:166-172

there are two separate questions to answer in 'OnMessageRaised' in these loggers:

  • should I care about this message?
  • do I log it now or at the end of the project build?

for the first question, you check by comparing verbosity to the messageimportance.
for the second, if the ProjectData is nonnull you should always buffer the message for later writing.

this is an either-or scenario - we should never both buffer a message and write it immediately

…ctor GitHub Actions and GitLab loggers to use ProjectTrackingLoggerBase

Co-authored-by: baronfel <573979+baronfel@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Nov 8, 2025

@copilot src/MSBuild/CICDLogger/AzureDevOps/AzureDevOpsLogger.cs:166-172

there are two separate questions to answer in 'OnMessageRaised' in these loggers:...

Fixed in 689a282. The logic now properly implements the either-or pattern:

  1. First checks if we should care about the message based on verbosity
  2. If yes, then checks projectData - buffers if non-null, writes immediately if null
  3. Never both buffers and writes the same message

Also applied this same pattern consistently to GitHub Actions and GitLab loggers.

Copilot finished work on behalf of baronfel November 8, 2025 16:46
@baronfel
Copy link
Member

baronfel commented Nov 8, 2025

@copilot src/MSBuild/CICDLogger/GitHubActions/GitHubActionsLogger.cs:55

for the github actions logger, the verbosity set by the user can be overridden to 'diagnostic' verbosity by the ACTIONS_STEP_DEBUG environment variable. If this variable is true, the logger verbosity must be set to diagnostic.

src/MSBuild/CICDLogger/GitHubActions/GitHubActionsLogger.cs:272-309 much like in the azdo logger, there's a lot of duplication here. consolidate this so that diagnostics share code as much as possible. check if the gitlab logger is doing the same and update it accordingly.

…plement timestamp-ordered events, and add GitHub Step Summary

Co-authored-by: baronfel <573979+baronfel@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Nov 8, 2025

@copilot src/MSBuild/CICDLogger/GitHubActions/GitHubActionsLogger.cs:55

for the github actions logger, the verbosity set by the user can be overridden to 'diagnostic' verbosity by the ACTIONS_STEP_DE...

Fixed in fbb6d24:

  1. ACTIONS_STEP_DEBUG support: Added override of Initialize method to check for ACTIONS_STEP_DEBUG environment variable and force Verbosity to Diagnostic when set.

  2. Consolidated diagnostic formatting: Replaced separate WriteError and WriteWarning methods with a single WriteDiagnostic method that takes the type as a parameter. Applied this pattern to all three loggers (GitHub Actions, Azure DevOps, GitLab).

  3. Timestamp-ordered events: Introduced TimestampedBuildEvent wrapper class to track event timestamps. All events (errors, warnings, messages) are now buffered in a single list and output in timestamp order using OrderBy(e => e.Timestamp) at project completion.

  4. GitHub Step Summary: Added WriteStepSummary method that writes a markdown-formatted build summary to the GITHUB_STEP_SUMMARY file, including:

    • Overall build status (✅/❌)
    • Total errors and warnings count
    • Per-project details with target framework and runtime identifier
    • Collapsible diagnostics sections ordered by timestamp
    • Properly formatted with emojis and markdown styling

Copilot finished work on behalf of baronfel November 8, 2025 17:07
@baronfel
Copy link
Member

baronfel commented Nov 8, 2025

@copilot src/MSBuild/CICDLogger/GitLab/GitLabLogger.cs:303
for legibility only the type should be colorized in the gitlab logger

…ibility

Co-authored-by: baronfel <573979+baronfel@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Nov 8, 2025

@copilot src/MSBuild/CICDLogger/GitLab/GitLabLogger.cs:303
for legibility only the type should be colorized in the gitlab logger

Fixed in a5ce9b1. The color reset (\x1b[0m) is now applied immediately after the type string, so only "ERROR" or "WARNING" is colorized. The rest of the diagnostic (file path, line numbers, code, and message) now appears in the default terminal color for better legibility.

@baronfel baronfel marked this pull request as ready for review November 8, 2025 17:13
Copilot finished work on behalf of baronfel November 8, 2025 17:14
@baronfel
Copy link
Member

baronfel commented Nov 8, 2025

@copilot these new loggers should moved into the Microsoft.Build.csproj and be in the src/Build/Logging/ directory - we want them to be accessible through the MSBuild APIs by folks using our libraries, not exclusive to the MSBuild command-line experience.

Co-authored-by: baronfel <573979+baronfel@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Nov 8, 2025

@copilot these new loggers should moved into the Microsoft.Build.csproj and be in the src/Build/Logging/ directory - we want them to be accessible through the MSBuild APIs by folks using our libra...

Fixed in 7847339. Moved all CI/CD loggers from src/MSBuild/CICDLogger/ to src/Build/Logging/CICDLogger/ and updated:

  • Namespaces changed from Microsoft.Build.CommandLine.CICDLogger.* to Microsoft.Build.Logging.CICDLogger.*
  • Removed compile entries from MSBuild.csproj and added wildcard pattern Logging\CICDLogger\**\*.cs to Microsoft.Build.csproj
  • Updated using statements in XMake.cs and all test files
  • Fixed nullability warnings and removed unnecessary using directives

The loggers are now accessible through the MSBuild APIs in the Microsoft.Build assembly.

Copilot finished work on behalf of baronfel November 8, 2025 17:53
@baronfel
Copy link
Member

baronfel commented Nov 8, 2025

@copilot many of the existing tests fail when run in Azure Devops on our own test pipelines. Run all of our tests but explicitly that that TF_BUILD environment variable and observe which tests fail. Then, update those tests to explicitly use either the console logger or the terminal logger (based on the needs of the test in question).

…o-detection

Co-authored-by: baronfel <573979+baronfel@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Nov 8, 2025

@copilot many of the existing tests fail when run in Azure Devops on our own test pipelines. Run all of our tests but explicitly that that TF_BUILD environment variable and observe which tests fail....

Fixed in 7df4cd9. Updated tests to explicitly use ConsoleLogger to prevent CI/CD logger auto-detection:

  1. XMake_Tests.cs: Modified ExecuteMSBuildExe helper to add -logger:ConsoleLogger to all MSBuild invocations
  2. MSBuildServer_Tests.cs: Added ExecMSBuildWithConsoleLogger helper method and updated all 16 ExecMSBuild calls to use it
  3. PerfLog_Tests.cs: Added -logger:ConsoleLogger to both test methods that execute MSBuild

These changes ensure tests use the expected ConsoleLogger instead of the Azure DevOps logger when TF_BUILD environment variable is set in CI pipelines.

Copilot finished work on behalf of baronfel November 8, 2025 18:47
@baronfel
Copy link
Member

baronfel commented Nov 8, 2025

@copilot the Microsoft.Build.BuildCheck.UnitTests.EndToEndTests and Microsoft.Build.UnitTests.XMakeAppTests are failing for similar reasons - they are assuming console output. Update them as well.

…gger auto-detection

Co-authored-by: baronfel <573979+baronfel@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Nov 8, 2025

@copilot the Microsoft.Build.BuildCheck.UnitTests.EndToEndTests and Microsoft.Build.UnitTests.XMakeAppTests are failing for similar reasons - they are assuming console output. Update them as well.

Fixed in 7393fcb. Added ExecBootstrapedMSBuildWithConsoleLogger helper method in EndToEndTests.cs and updated all test methods to use it, ensuring tests explicitly use ConsoleLogger instead of auto-detecting Azure DevOps logger when TF_BUILD is set.

The XMakeAppTests were already fixed in commit 7df4cd9 through the ExecuteMSBuildExe helper method.

Copilot finished work on behalf of baronfel November 8, 2025 19:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants