diff --git a/SpecFlow.Tools.MsBuild.Generation/GenerateFeatureFileCodeBehindTaskContainerBuilder.cs b/SpecFlow.Tools.MsBuild.Generation/GenerateFeatureFileCodeBehindTaskContainerBuilder.cs index 583f8ace4..85803d3f4 100644 --- a/SpecFlow.Tools.MsBuild.Generation/GenerateFeatureFileCodeBehindTaskContainerBuilder.cs +++ b/SpecFlow.Tools.MsBuild.Generation/GenerateFeatureFileCodeBehindTaskContainerBuilder.cs @@ -3,6 +3,7 @@ using TechTalk.SpecFlow.Analytics; using TechTalk.SpecFlow.Analytics.AppInsights; using TechTalk.SpecFlow.Analytics.UserId; +using TechTalk.SpecFlow.EnvironmentAccess; using TechTalk.SpecFlow.Generator.Project; namespace SpecFlow.Tools.MsBuild.Generation @@ -36,6 +37,7 @@ public IObjectContainer BuildRootContainer( objectContainer.RegisterTypeAs(); objectContainer.RegisterTypeAs(); objectContainer.RegisterTypeAs(); + objectContainer.RegisterTypeAs(); objectContainer.RegisterTypeAs(); objectContainer.RegisterTypeAs(); diff --git a/TechTalk.SpecFlow/Analytics/AnalyticsEventProvider.cs b/TechTalk.SpecFlow/Analytics/AnalyticsEventProvider.cs index b084af2fc..5acfb02ee 100644 --- a/TechTalk.SpecFlow/Analytics/AnalyticsEventProvider.cs +++ b/TechTalk.SpecFlow/Analytics/AnalyticsEventProvider.cs @@ -4,17 +4,22 @@ using TechTalk.SpecFlow.Analytics.UserId; using TechTalk.SpecFlow.UnitTestProvider; using System.Runtime.InteropServices; +using System.Collections.Generic; +using TechTalk.SpecFlow.EnvironmentAccess; +using TechTalk.SpecFlow.CommonModels; namespace TechTalk.SpecFlow.Analytics { public class AnalyticsEventProvider : IAnalyticsEventProvider { private readonly IUserUniqueIdStore _userUniqueIdStore; + private readonly IEnvironmentWrapper _environmentWrapper; private readonly string _unitTestProvider; - public AnalyticsEventProvider(IUserUniqueIdStore userUniqueIdStore, UnitTestProviderConfiguration unitTestProviderConfiguration) + public AnalyticsEventProvider(IUserUniqueIdStore userUniqueIdStore, UnitTestProviderConfiguration unitTestProviderConfiguration, IEnvironmentWrapper environmentWrapper) { _userUniqueIdStore = userUniqueIdStore; + _environmentWrapper = environmentWrapper; _unitTestProvider = unitTestProviderConfiguration.UnitTestProvider; } @@ -23,7 +28,7 @@ public SpecFlowProjectCompilingEvent CreateProjectCompilingEvent(string msbuildV string userId = _userUniqueIdStore.GetUserId(); string unitTestProvider = _unitTestProvider; string specFlowVersion = GetSpecFlowVersion(); - bool isBuildServer = IsBuildServerMode(); + string buildServerName = GetBuildServerName(); bool isDockerContainer = IsRunningInDockerContainer(); string hashedAssemblyName = ToSha256(assemblyName); string platform = GetOSPlatform(); @@ -36,7 +41,7 @@ public SpecFlowProjectCompilingEvent CreateProjectCompilingEvent(string msbuildV platformDescription, specFlowVersion, unitTestProvider, - isBuildServer, + buildServerName, hashedAssemblyName, targetFrameworks, targetFramework, @@ -52,10 +57,10 @@ public SpecFlowProjectRunningEvent CreateProjectRunningEvent(string testAssembly string userId = _userUniqueIdStore.GetUserId(); string unitTestProvider = _unitTestProvider; string specFlowVersion = GetSpecFlowVersion(); - bool isBuildServer = IsBuildServerMode(); string targetFramework = GetNetCoreVersion() ?? Environment.Version.ToString(); bool isDockerContainer = IsRunningInDockerContainer(); - + string buildServerName = GetBuildServerName(); + string hashedAssemblyName = ToSha256(testAssemblyName); string platform = GetOSPlatform(); string platformDescription = RuntimeInformation.OSDescription; @@ -67,7 +72,7 @@ public SpecFlowProjectRunningEvent CreateProjectRunningEvent(string testAssembly platformDescription, specFlowVersion, unitTestProvider, - isBuildServer, + buildServerName, hashedAssemblyName, null, targetFramework, @@ -95,17 +100,32 @@ private string GetOSPlatform() throw new InvalidOperationException("Platform cannot be identified"); } - private bool IsBuildServerMode() + private readonly Dictionary buildServerTypes + = new Dictionary { + { "TF_BUILD","Azure Pipelines"}, + { "TEAMCITY_VERSION","TeamCity"}, + { "JENKINS_HOME","Jenkins"}, + { "GITHUB_ACTIONS","GitHub Actions"}, + { "GITLAB_CI","GitLab CI/CD"}, + { "CODEBUILD_BUILD_ID","AWS CodeBuild"}, + { "TRAVIS","Travis CI"}, + { "APPVEYOR","AppVeyor"}, + }; + + private string GetBuildServerName() { - bool isRunByTfs = !string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("TF_BUILD")); - bool isRunByTeamCity = !string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("TEAMCITY_VERSION")); - - return isRunByTfs || isRunByTeamCity; + foreach (var buildServerType in buildServerTypes) + { + var envVariable = _environmentWrapper.GetEnvironmentVariable(buildServerType.Key); + if (envVariable is ISuccess) + return buildServerType.Value; + } + return null; } private bool IsRunningInDockerContainer() { - return !string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER")); + return _environmentWrapper.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER") is ISuccess; } private string GetSpecFlowVersion() diff --git a/TechTalk.SpecFlow/Analytics/AppInsights/AppInsightsEventTelemetry.cs b/TechTalk.SpecFlow/Analytics/AppInsights/AppInsightsEventTelemetry.cs index de816c7a9..d85cae80e 100644 --- a/TechTalk.SpecFlow/Analytics/AppInsights/AppInsightsEventTelemetry.cs +++ b/TechTalk.SpecFlow/Analytics/AppInsights/AppInsightsEventTelemetry.cs @@ -53,6 +53,7 @@ public AppInsightsEventTelemetry(IAnalyticsEvent analyticsEvent) { "SpecFlowVersion", analyticsEvent.SpecFlowVersion }, { "UnitTestProvider", analyticsEvent.UnitTestProvider ?? DefaultValue }, { "IsBuildServer", analyticsEvent.IsBuildServer.ToString() }, + { "BuildServerName", analyticsEvent.BuildServerName ?? DefaultValue }, { "IsDockerContainer", analyticsEvent.IsDockerContainer.ToString() }, { "HashedAssemblyName", analyticsEvent.HashedAssemblyName ?? DefaultValue }, { "TargetFrameworks", analyticsEvent.TargetFrameworks }, diff --git a/TechTalk.SpecFlow/Analytics/IAnalyticsEvent.cs b/TechTalk.SpecFlow/Analytics/IAnalyticsEvent.cs index 57ef7728c..4fb72a843 100644 --- a/TechTalk.SpecFlow/Analytics/IAnalyticsEvent.cs +++ b/TechTalk.SpecFlow/Analytics/IAnalyticsEvent.cs @@ -13,6 +13,7 @@ public interface IAnalyticsEvent string SpecFlowVersion { get; } string UnitTestProvider { get; } bool IsBuildServer { get; } + string BuildServerName { get; } bool IsDockerContainer { get; } string HashedAssemblyName { get;} string TargetFrameworks { get; } diff --git a/TechTalk.SpecFlow/Analytics/SpecFlowAnalyticsEventBase.cs b/TechTalk.SpecFlow/Analytics/SpecFlowAnalyticsEventBase.cs index 68e7c6861..468254db9 100644 --- a/TechTalk.SpecFlow/Analytics/SpecFlowAnalyticsEventBase.cs +++ b/TechTalk.SpecFlow/Analytics/SpecFlowAnalyticsEventBase.cs @@ -12,12 +12,13 @@ public abstract class SpecFlowAnalyticsEventBase : IAnalyticsEvent public string SpecFlowVersion { get; } public string UnitTestProvider { get; } public bool IsBuildServer { get; } + public string BuildServerName { get; } public string HashedAssemblyName { get; } public string TargetFrameworks { get; } public string TargetFramework { get; } public bool IsDockerContainer { get; } - protected SpecFlowAnalyticsEventBase(DateTime utcDate, string userId, string platform, string platformDescription, string specFlowVersion, string unitTestProvider, bool isBuildServer, string hashedAssemblyName, string targetFrameworks, string targetFramework, bool isDockerContainer) + protected SpecFlowAnalyticsEventBase(DateTime utcDate, string userId, string platform, string platformDescription, string specFlowVersion, string unitTestProvider, string buildServerName, string hashedAssemblyName, string targetFrameworks, string targetFramework, bool isDockerContainer) { UtcDate = utcDate; UserId = userId; @@ -25,7 +26,8 @@ protected SpecFlowAnalyticsEventBase(DateTime utcDate, string userId, string pla PlatformDescription = platformDescription; SpecFlowVersion = specFlowVersion; UnitTestProvider = unitTestProvider; - IsBuildServer = isBuildServer; + BuildServerName = buildServerName; + IsBuildServer = !string.IsNullOrWhiteSpace(buildServerName); HashedAssemblyName = hashedAssemblyName; TargetFrameworks = targetFrameworks; TargetFramework = targetFramework; diff --git a/TechTalk.SpecFlow/Analytics/SpecFlowProjectCompilingEvent.cs b/TechTalk.SpecFlow/Analytics/SpecFlowProjectCompilingEvent.cs index 7667b479f..36da6b394 100644 --- a/TechTalk.SpecFlow/Analytics/SpecFlowProjectCompilingEvent.cs +++ b/TechTalk.SpecFlow/Analytics/SpecFlowProjectCompilingEvent.cs @@ -7,7 +7,7 @@ public class SpecFlowProjectCompilingEvent : SpecFlowAnalyticsEventBase public string MSBuildVersion { get; } public string ProjectGuid { get; set; } - public SpecFlowProjectCompilingEvent(DateTime utcDate, string userId, string platform, string platformDescription, string specFlowVersion, string unitTestProvider, bool isBuildServer, string hashedAssemblyName, string targetFrameworks, string targetFramework, string msBuildVersion, string projectGuid, bool isDockerContainer) : base(utcDate, userId, platform, platformDescription, specFlowVersion, unitTestProvider, isBuildServer, hashedAssemblyName, targetFrameworks, targetFramework, isDockerContainer) + public SpecFlowProjectCompilingEvent(DateTime utcDate, string userId, string platform, string platformDescription, string specFlowVersion, string unitTestProvider, string buildServerName, string hashedAssemblyName, string targetFrameworks, string targetFramework, string msBuildVersion, string projectGuid, bool isDockerContainer) : base(utcDate, userId, platform, platformDescription, specFlowVersion, unitTestProvider, buildServerName, hashedAssemblyName, targetFrameworks, targetFramework, isDockerContainer) { MSBuildVersion = msBuildVersion; ProjectGuid = projectGuid; diff --git a/TechTalk.SpecFlow/Analytics/SpecFlowProjectRunningEvent.cs b/TechTalk.SpecFlow/Analytics/SpecFlowProjectRunningEvent.cs index 4d7ec0816..212a3d615 100644 --- a/TechTalk.SpecFlow/Analytics/SpecFlowProjectRunningEvent.cs +++ b/TechTalk.SpecFlow/Analytics/SpecFlowProjectRunningEvent.cs @@ -4,7 +4,7 @@ namespace TechTalk.SpecFlow.Analytics { public class SpecFlowProjectRunningEvent : SpecFlowAnalyticsEventBase { - public SpecFlowProjectRunningEvent(DateTime utcDate, string userId, string platform, string platformDescription, string specFlowVersion, string unitTestProvider, bool isBuildServer, string hashedAssemblyName, string targetFrameworks, string targetFramework, bool isDockerContainer) : base(utcDate, userId, platform, platformDescription, specFlowVersion, unitTestProvider, isBuildServer, hashedAssemblyName, targetFrameworks, targetFramework, isDockerContainer) + public SpecFlowProjectRunningEvent(DateTime utcDate, string userId, string platform, string platformDescription, string specFlowVersion, string unitTestProvider, string buildServerName, string hashedAssemblyName, string targetFrameworks, string targetFramework, bool isDockerContainer) : base(utcDate, userId, platform, platformDescription, specFlowVersion, unitTestProvider, buildServerName, hashedAssemblyName, targetFrameworks, targetFramework, isDockerContainer) { } diff --git a/Tests/TechTalk.SpecFlow.RuntimeTests/Analytics/AnalyticsEventProviderTests.cs b/Tests/TechTalk.SpecFlow.RuntimeTests/Analytics/AnalyticsEventProviderTests.cs new file mode 100644 index 000000000..cf26bf3c4 --- /dev/null +++ b/Tests/TechTalk.SpecFlow.RuntimeTests/Analytics/AnalyticsEventProviderTests.cs @@ -0,0 +1,62 @@ +using FluentAssertions; +using Moq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TechTalk.SpecFlow.Analytics; +using TechTalk.SpecFlow.Analytics.UserId; +using TechTalk.SpecFlow.CommonModels; +using TechTalk.SpecFlow.EnvironmentAccess; +using Xunit; + +namespace TechTalk.SpecFlow.RuntimeTests.Analytics +{ + public class AnalyticsEventProviderTests + { + [Fact] + public void Should_return_the_build_server_name_in_Compiling_Event() + { + var userUniqueIdStoreMock = new Mock(); + var environmentMock = new Mock(); + var sut = new AnalyticsEventProvider(userUniqueIdStoreMock.Object, new UnitTestProvider.UnitTestProviderConfiguration(), environmentMock.Object); + + environmentMock + .Setup(m => m.GetEnvironmentVariable("TF_BUILD")) + .Returns(new Success("true")); + + var compilingEvent = sut.CreateProjectCompilingEvent(null, null, null, null, null); + + compilingEvent.BuildServerName.Should().Be("Azure Pipelines"); + } + + [Fact] + public void Should_return_the_build_server_name_in_Running_Event() + { + var userUniqueIdStoreMock = new Mock(); + var environmentMock = new Mock(); + var sut = new AnalyticsEventProvider(userUniqueIdStoreMock.Object, new UnitTestProvider.UnitTestProviderConfiguration(), environmentMock.Object); + + environmentMock + .Setup(m => m.GetEnvironmentVariable("TEAMCITY_VERSION")) + .Returns(new Success("true")); + + var compilingEvent = sut.CreateProjectRunningEvent(null); + + compilingEvent.BuildServerName.Should().Be("TeamCity"); + } + + [Fact] + public void Should_return_null_for_the_build_server_name_when_not_detected() + { + var userUniqueIdStoreMock = new Mock(); + var environmentMock = new Mock(); + var sut = new AnalyticsEventProvider(userUniqueIdStoreMock.Object, new UnitTestProvider.UnitTestProviderConfiguration(), environmentMock.Object); + + var compilingEvent = sut.CreateProjectRunningEvent(null); + + compilingEvent.BuildServerName.Should().Be(null); + } + } +}