diff --git a/eng/vendored-files.json b/eng/vendored-files.json index afd5faebec..e2598745b7 100644 --- a/eng/vendored-files.json +++ b/eng/vendored-files.json @@ -192,7 +192,7 @@ { "id": "platform-ci-environment-detector", "local_path": "src/Platform/Microsoft.Testing.Platform/Helpers/CIEnvironmentDetector.cs", - "notes": "Adapted from dotnet CLI telemetry CI detection. Maintained per https://learn.microsoft.com/dotnet/core/tools/telemetry#continuous-integration-detection.", + "notes": "Adapted from dotnet CLI telemetry CI detection. Maintained per https://learn.microsoft.com/dotnet/core/tools/telemetry#continuous-integration-detection. This file is the single source of truth: it is linked into MSTest.TestFramework via src/TestFramework/TestFramework/TestFramework.csproj and toggled via the IS_CORE_MTP define.", "sources": [ { "repo": "dotnet/sdk", @@ -294,21 +294,6 @@ } ] }, - { - "id": "testframework-ci-environment-detector", - "local_path": "src/TestFramework/TestFramework/Internal/CIEnvironmentDetector.cs", - "notes": "Independent in-tree copy of the CI detector (test-framework variant exposing an IEnvironment-backed Instance) sharing the rules with the platform copy.", - "sources": [ - { - "repo": "dotnet/sdk", - "ref": "main", - "path": "src/Cli/Microsoft.DotNet.Cli.Definitions/Telemetry/CIEnvironmentDetectorForTelemetry.cs", - "baseline_ref_sha": "1ab3ae8e0338cdd06b3974959c5802ccc5a85978", - "baseline_blob_sha": "e10e1fc2cd973c6123fd983b16a8f0c1e9191c31", - "scope": "CI detection rules and environment variable lists" - } - ] - }, { "id": "source-gen-equatable-array", "local_path": "src/Analyzers/MSTest.SourceGeneration/Helpers/EquatableArray{T}.cs", diff --git a/src/Platform/Microsoft.Testing.Platform/Helpers/CIEnvironmentDetector.cs b/src/Platform/Microsoft.Testing.Platform/Helpers/CIEnvironmentDetector.cs index f8f91094c9..4b62cf6c16 100644 --- a/src/Platform/Microsoft.Testing.Platform/Helpers/CIEnvironmentDetector.cs +++ b/src/Platform/Microsoft.Testing.Platform/Helpers/CIEnvironmentDetector.cs @@ -1,14 +1,27 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +// NOTE: This file is the single source of truth for CI environment detection. It is the canonical +// copy for Microsoft.Testing.Platform and is also linked into Microsoft.Testing.Extensions.Telemetry +// (via Microsoft.Testing.Extensions.Telemetry.csproj) and MSTest.TestFramework (via +// src/TestFramework/TestFramework/TestFramework.csproj). The TESTFRAMEWORK_CI_DETECTOR define +// is set only in the MSTest.TestFramework project; the #if blocks below toggle namespace, +// attributes, constructor accessibility, the static Instance helper, and the IsNullOrEmpty +// implementation so the file fits both the Platform/Telemetry layer and the TestFramework layer. +#if TESTFRAMEWORK_CI_DETECTOR +namespace Microsoft.VisualStudio.TestTools.UnitTesting; +#else using Microsoft.CodeAnalysis; namespace Microsoft.Testing.Platform.Helpers; +#endif // Detection of CI: https://learn.microsoft.com/dotnet/core/tools/telemetry#continuous-integration-detection // Based on: https://github.com/dotnet/sdk/blob/main/src/Cli/Microsoft.DotNet.Cli.Definitions/Telemetry/CIEnvironmentDetectorForTelemetry.cs +#if !TESTFRAMEWORK_CI_DETECTOR [Embedded] [ExcludeFromCodeCoverage] +#endif internal sealed class CIEnvironmentDetector { // Systems that provide boolean values only, so we can simply parse and check for true @@ -58,12 +71,23 @@ internal sealed class CIEnvironmentDetector private readonly IEnvironment _environment; +#if TESTFRAMEWORK_CI_DETECTOR + /// + /// Gets the default instance that uses the real environment. + /// + public static CIEnvironmentDetector Instance { get; } = new(EnvironmentWrapper.Instance); +#endif + /// /// Initializes a new instance of the class. /// /// The environment abstraction to use for reading environment variables. +#if TESTFRAMEWORK_CI_DETECTOR + internal /* for testing purposes */ CIEnvironmentDetector(IEnvironment environment) => _environment = environment; +#else public CIEnvironmentDetector(IEnvironment environment) => _environment = environment; +#endif /// /// Detects if the current environment is a CI environment. @@ -84,7 +108,7 @@ public bool IsCIEnvironment() bool allVariablesPresent = true; foreach (string variable in variables) { - if (global::Microsoft.Testing.Platform.RoslynString.IsNullOrEmpty(_environment.GetEnvironmentVariable(variable))) + if (IsNullOrEmpty(_environment.GetEnvironmentVariable(variable))) { allVariablesPresent = false; break; @@ -99,7 +123,7 @@ public bool IsCIEnvironment() foreach (string variable in IfNonNullVariables) { - if (!global::Microsoft.Testing.Platform.RoslynString.IsNullOrEmpty(_environment.GetEnvironmentVariable(variable))) + if (!IsNullOrEmpty(_environment.GetEnvironmentVariable(variable))) { return true; } @@ -107,4 +131,12 @@ public bool IsCIEnvironment() return false; } + +#if TESTFRAMEWORK_CI_DETECTOR + private static bool IsNullOrEmpty(string? value) + => string.IsNullOrEmpty(value); +#else + private static bool IsNullOrEmpty(string? value) + => global::Microsoft.Testing.Platform.RoslynString.IsNullOrEmpty(value); +#endif } diff --git a/src/TestFramework/TestFramework/Internal/CIEnvironmentDetector.cs b/src/TestFramework/TestFramework/Internal/CIEnvironmentDetector.cs deleted file mode 100644 index 2a59282f82..0000000000 --- a/src/TestFramework/TestFramework/Internal/CIEnvironmentDetector.cs +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace Microsoft.VisualStudio.TestTools.UnitTesting; - -/// -/// Provides CI environment detection capabilities. -/// -/// -/// Based on https://learn.microsoft.com/dotnet/core/tools/telemetry#continuous-integration-detection -/// and https://github.com/dotnet/sdk/blob/main/src/Cli/dotnet/Telemetry/CIEnvironmentDetectorForTelemetry.cs. -/// -internal sealed class CIEnvironmentDetector -{ - /// - /// Gets the default instance that uses the real environment. - /// - public static CIEnvironmentDetector Instance { get; } = new(EnvironmentWrapper.Instance); - - private readonly IEnvironment _environment; - - // Systems that provide boolean values only, so we can simply parse and check for true - private static readonly string[] BooleanVariables = - [ - // Azure Pipelines - https://docs.microsoft.com/azure/devops/pipelines/build/variables#system-variables-devops-services - "TF_BUILD", - - // GitHub Actions - https://docs.github.com/en/actions/learn-github-actions/environment-variables#default-environment-variables - "GITHUB_ACTIONS", - - // AppVeyor - https://www.appveyor.com/docs/environment-variables/ - "APPVEYOR", - - // A general-use flag - Many of the major players support this: AzDo, GitHub, GitLab, AppVeyor, Travis CI, CircleCI. - "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", - ]; - - // Systems where every variable must be present and not-null before returning true - private static readonly string[][] AllNotNullVariables = - [ - // AWS CodeBuild - https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-env-vars.html - ["CODEBUILD_BUILD_ID", "AWS_REGION"], - - // Jenkins - https://github.com/jenkinsci/jenkins/blob/master/core/src/main/resources/jenkins/model/CoreEnvironmentContributor/buildEnv.groovy - ["BUILD_ID", "BUILD_URL"], - - // Google Cloud Build - https://cloud.google.com/build/docs/configuring-builds/substitute-variable-values#using_default_substitutions - ["BUILD_ID", "PROJECT_ID"], - ]; - - // Systems where the variable must be present and not-null - private static readonly string[] IfNonNullVariables = - [ - // TeamCity - https://www.jetbrains.com/help/teamcity/predefined-build-parameters.html#Predefined+Server+Build+Parameters - "TEAMCITY_VERSION", - - // JetBrains Space - https://www.jetbrains.com/help/space/automation-environment-variables.html#general - "JB_SPACE_API_URL", - ]; - - /// - /// Initializes a new instance of the class. - /// - /// The environment abstraction to use for reading environment variables. - internal /* for testing purposes */ 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) - { - return true; - } - } - - foreach (string[] variables in AllNotNullVariables) - { - bool allVariablesPresent = true; - foreach (string variable in variables) - { - if (string.IsNullOrEmpty(_environment.GetEnvironmentVariable(variable))) - { - allVariablesPresent = false; - break; - } - } - - if (allVariablesPresent) - { - return true; - } - } - - foreach (string variable in IfNonNullVariables) - { - if (!string.IsNullOrEmpty(_environment.GetEnvironmentVariable(variable))) - { - return true; - } - } - - return false; - } -} diff --git a/src/TestFramework/TestFramework/TestFramework.csproj b/src/TestFramework/TestFramework/TestFramework.csproj index 6afb0f4f90..a167fe2984 100644 --- a/src/TestFramework/TestFramework/TestFramework.csproj +++ b/src/TestFramework/TestFramework/TestFramework.csproj @@ -26,8 +26,16 @@ + + + + $(DefineConstants);TESTFRAMEWORK_CI_DETECTOR + +