diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightsProvider.cs b/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightsProvider.cs index 647c516d13..edd545de3c 100644 --- a/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightsProvider.cs +++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightsProvider.cs @@ -93,7 +93,7 @@ public AppInsightsProvider( string sessionId) { _ = bool.TryParse(configuration[PlatformConfigurationConstants.PlatformTelemetryIsDevelopmentRepository], out _isDevelopmentRepository); - _isCi = CIEnvironmentDetectorForTelemetry.IsCIEnvironment(); + _isCi = new CIEnvironmentDetector(environment).IsCIEnvironment(); _environment = environment; _currentSessionId = sessionId; _testApplicationCancellationTokenSource = testApplicationCancellationTokenSource; diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/Microsoft.Testing.Extensions.Telemetry.csproj b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Microsoft.Testing.Extensions.Telemetry.csproj index 9817dd8471..1c9ee840cf 100644 --- a/src/Platform/Microsoft.Testing.Extensions.Telemetry/Microsoft.Testing.Extensions.Telemetry.csproj +++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Microsoft.Testing.Extensions.Telemetry.csproj @@ -7,6 +7,7 @@ + diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/CIEnvironmentDetectorForTelemetry.cs b/src/Platform/Microsoft.Testing.Platform/Helpers/CIEnvironmentDetector.cs similarity index 63% rename from src/Platform/Microsoft.Testing.Extensions.Telemetry/CIEnvironmentDetectorForTelemetry.cs rename to src/Platform/Microsoft.Testing.Platform/Helpers/CIEnvironmentDetector.cs index 0ac25bde4a..f8f91094c9 100644 --- a/src/Platform/Microsoft.Testing.Extensions.Telemetry/CIEnvironmentDetectorForTelemetry.cs +++ b/src/Platform/Microsoft.Testing.Platform/Helpers/CIEnvironmentDetector.cs @@ -1,13 +1,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using Microsoft.Testing.Platform; +using Microsoft.CodeAnalysis; -namespace Microsoft.Testing.Extensions.Telemetry; +namespace Microsoft.Testing.Platform.Helpers; // Detection of CI: https://learn.microsoft.com/dotnet/core/tools/telemetry#continuous-integration-detection -// From: https://github.com/dotnet/sdk/blob/main/src/Cli/dotnet/Telemetry/CIEnvironmentDetectorForTelemetry.cs -internal sealed class CIEnvironmentDetectorForTelemetry +// Based on: https://github.com/dotnet/sdk/blob/main/src/Cli/Microsoft.DotNet.Cli.Definitions/Telemetry/CIEnvironmentDetectorForTelemetry.cs +[Embedded] +[ExcludeFromCodeCoverage] +internal sealed class CIEnvironmentDetector { // Systems that provide boolean values only, so we can simply parse and check for true private static readonly string[] BooleanVariables = @@ -22,14 +24,13 @@ internal sealed class CIEnvironmentDetectorForTelemetry "APPVEYOR", // A general-use flag - Many of the major players support this: AzDo, GitHub, GitLab, AppVeyor, Travis CI, CircleCI. - // Given this, we could potentially remove all of these other options? "CI", // Travis CI - https://docs.travis-ci.com/user/environment-variables/#default-environment-variables "TRAVIS", // CircleCI - https://circleci.com/docs/2.0/env-vars/#built-in-environment-variables - "CIRCLECI" + "CIRCLECI", ]; // Systems where every variable must be present and not-null before returning true @@ -52,14 +53,27 @@ internal sealed class CIEnvironmentDetectorForTelemetry "TEAMCITY_VERSION", // JetBrains Space - https://www.jetbrains.com/help/space/automation-environment-variables.html#general - "JB_SPACE_API_URL" + "JB_SPACE_API_URL", ]; - public static bool IsCIEnvironment() + private readonly IEnvironment _environment; + + /// + /// Initializes a new instance of the class. + /// + /// The environment abstraction to use for reading environment variables. + public CIEnvironmentDetector(IEnvironment environment) + => _environment = environment; + + /// + /// Detects if the current environment is a CI environment. + /// + /// true if running in a CI environment; otherwise, false. + public bool IsCIEnvironment() { foreach (string booleanVariable in BooleanVariables) { - if (bool.TryParse(Environment.GetEnvironmentVariable(booleanVariable), out bool envVar) && envVar) + if (bool.TryParse(_environment.GetEnvironmentVariable(booleanVariable), out bool envVar) && envVar) { return true; } @@ -67,7 +81,17 @@ public static bool IsCIEnvironment() foreach (string[] variables in AllNotNullVariables) { - if (variables.All(variable => !RoslynString.IsNullOrEmpty(Environment.GetEnvironmentVariable(variable)))) + bool allVariablesPresent = true; + foreach (string variable in variables) + { + if (global::Microsoft.Testing.Platform.RoslynString.IsNullOrEmpty(_environment.GetEnvironmentVariable(variable))) + { + allVariablesPresent = false; + break; + } + } + + if (allVariablesPresent) { return true; } @@ -75,7 +99,7 @@ public static bool IsCIEnvironment() foreach (string variable in IfNonNullVariables) { - if (!RoslynString.IsNullOrEmpty(Environment.GetEnvironmentVariable(variable))) + if (!global::Microsoft.Testing.Platform.RoslynString.IsNullOrEmpty(_environment.GetEnvironmentVariable(variable))) { return true; } diff --git a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/SimpleAnsiTerminal.cs b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/SimpleAnsiTerminal.cs index 12b4f4eee0..84656db087 100644 --- a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/SimpleAnsiTerminal.cs +++ b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/SimpleAnsiTerminal.cs @@ -6,8 +6,8 @@ namespace Microsoft.Testing.Platform.OutputDevice.Terminal; /// -/// Simple terminal that uses 4-bit ANSI for colors but does not move cursor and does not do other fancy stuff to stay compatible with CI systems like AzDO. -/// The colors are set on start of every line to properly color multiline strings in AzDO output. +/// Simple terminal that uses 4-bit ANSI for colors but does not move cursor and does not do other fancy stuff to stay compatible with CI systems. +/// The colors are set on start of every line to properly color multiline strings in CI log viewers that reset color state at each newline (e.g. Azure DevOps). /// internal sealed class SimpleAnsiTerminal : SimpleTerminal { diff --git a/src/Platform/Microsoft.Testing.Platform/OutputDevice/TerminalOutputDevice.cs b/src/Platform/Microsoft.Testing.Platform/OutputDevice/TerminalOutputDevice.cs index a3563ec9a2..623540dc95 100644 --- a/src/Platform/Microsoft.Testing.Platform/OutputDevice/TerminalOutputDevice.cs +++ b/src/Platform/Microsoft.Testing.Platform/OutputDevice/TerminalOutputDevice.cs @@ -142,8 +142,7 @@ await _policiesService.RegisterOnAbortCallbackAsync( _isServerMode = _commandLineOptions.IsOptionSet(PlatformCommandLineProvider.ServerOptionKey); bool noAnsi = _commandLineOptions.IsOptionSet(TerminalTestReporterCommandLineOptionsProvider.NoAnsiOption); - // TODO: Replace this with proper CI detection that we already have in telemetry. https://github.com/microsoft/testfx/issues/5533#issuecomment-2838893327 - bool inCI = string.Equals(_environment.GetEnvironmentVariable("TF_BUILD"), "true", StringComparison.OrdinalIgnoreCase) || string.Equals(_environment.GetEnvironmentVariable("GITHUB_ACTIONS"), "true", StringComparison.OrdinalIgnoreCase); + bool inCI = new CIEnvironmentDetector(_environment).IsCIEnvironment(); AnsiMode ansiMode = AnsiMode.AnsiIfPossible; // In LLM environments, prefer simple text output so that LLM can parse it easily.