Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor code sharing between extensions #191

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
using System;
using System.Collections.Generic;
using TechTalk.SpecFlow.IdeIntegration.Analytics;
using TechTalk.SpecFlow.IdeIntegration.Analytics.Events;
using TechTalk.SpecFlow.IdeIntegration.Install;

namespace TechTalk.SpecFlow.VsIntegration.Implementation.Analytics
namespace TechTalk.SpecFlow.IdeIntegration.Analytics
{
public class AnalyticsTransmitter : IAnalyticsTransmitter
{
private readonly IEnableAnalyticsChecker _enableAnalyticsChecker;
private readonly IAnalyticsTransmitterSink _analyticsTransmitterSink;

private readonly Lazy<string> _userUniqueId;
private readonly Lazy<string> _userUniqueId;
private readonly Lazy<string> _ideName;
private readonly Lazy<string> _ideVersion;
private readonly Lazy<IEnumerable<string>> _targetFrameworks;
Expand Down Expand Up @@ -64,44 +63,44 @@ public void TransmitExtensionInstalledEvent()
public void TransmitExtensionUpgradedEvent(string oldExtensionVersion)
{
Execute(() =>
new ExtensionUpgradedAnalyticsEvent(_ideName.Value, DateTime.UtcNow, _userUniqueId.Value, oldExtensionVersion, _extensionVersion.Value));
new ExtensionUpgradedAnalyticsEvent(_ideName.Value, DateTime.UtcNow, _userUniqueId.Value, _ideVersion.Value, oldExtensionVersion, _extensionVersion.Value));
}

public void TransmitExtensionUsage(int daysOfUsage)
{
Execute(() =>
new ExtensionUsageAnalyticsEvent(_ideName.Value, DateTime.UtcNow, _userUniqueId.Value, daysOfUsage));
new ExtensionUsageAnalyticsEvent(_ideName.Value, DateTime.UtcNow, _userUniqueId.Value, _ideVersion.Value, daysOfUsage));
}

public void TransmitProjectTemplateWizardStartedEvent()
{
Execute(() =>
new ProjectTemplateWizardStartedAnalyticsEvent(_ideName.Value, DateTime.UtcNow, _userUniqueId.Value));
new ProjectTemplateWizardStartedAnalyticsEvent(_ideName.Value, DateTime.UtcNow, _userUniqueId.Value, _ideVersion.Value));
}

public void TransmitProjectTemplateWizardCompletedEvent(string selectedDotNetFramework, string selectedUnitTestFramework)
{
Execute(() =>
new ProjectTemplateWizardCompletedAnalyticsEvent(_ideName.Value, DateTime.UtcNow, _userUniqueId.Value, selectedDotNetFramework, selectedUnitTestFramework));
new ProjectTemplateWizardCompletedAnalyticsEvent(_ideName.Value, DateTime.UtcNow, _userUniqueId.Value, _ideVersion.Value, selectedDotNetFramework, selectedUnitTestFramework));
}

public void TransmitNotificationShownEvent(string notificationId)
{
Execute(() =>
new NotificationShownAnalyticsEvent(_ideName.Value, DateTime.UtcNow, _userUniqueId.Value, notificationId));
new NotificationShownAnalyticsEvent(_ideName.Value, DateTime.UtcNow, _ideVersion.Value, _userUniqueId.Value, notificationId));
}

public void TransmitNotificationLinkOpenedEvent(string notificationId)
{
Execute(() =>
new NotificationLinkOpenedAnalyticsEvent(_ideName.Value, DateTime.UtcNow, _userUniqueId.Value, notificationId));
new NotificationLinkOpenedAnalyticsEvent(_ideName.Value, DateTime.UtcNow, _ideVersion.Value, _userUniqueId.Value, notificationId));
}

private void TransmitException(Exception exception)
{
try
{
var exceptionAnalyticsEvent = new ExceptionAnalyticsEvent(_ideName.Value, exception.GetType().ToString(), DateTime.UtcNow);
var exceptionAnalyticsEvent = new ExceptionAnalyticsEvent(_ideName.Value, _ideVersion.Value, exception.GetType().ToString(), DateTime.UtcNow);
_analyticsTransmitterSink.TransmitEvent(exceptionAnalyticsEvent);
}
catch (Exception)
Expand Down
31 changes: 31 additions & 0 deletions IdeIntegration/Analytics/AppInsightsAnalyticsTransmitterSink.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;

namespace TechTalk.SpecFlow.IdeIntegration.Analytics
{
public class AppInsightsAnalyticsTransmitterSink : IAnalyticsTransmitterSink
{
private readonly TelemetryClientWrapper _telemetryClientWrapper;
private readonly IEnableAnalyticsChecker _enableAnalyticsChecker;
private readonly IAppInsightsEventConverter _appInsightsEventConverter;

public AppInsightsAnalyticsTransmitterSink(TelemetryClientWrapper telemetryClientWrapper, IEnableAnalyticsChecker enableAnalyticsChecker, IAppInsightsEventConverter appInsightsEventConverter)
{
_telemetryClientWrapper = telemetryClientWrapper;
_enableAnalyticsChecker = enableAnalyticsChecker;
_appInsightsEventConverter = appInsightsEventConverter;
}

public void TransmitEvent(IAnalyticsEvent analyticsEvent)
{
if (!_enableAnalyticsChecker.IsEnabled())
{
throw new InvalidOperationException("This method should not be called because analytics transmission is disabled.");
}

var appInsightsEvent = _appInsightsEventConverter.ConvertToAppInsightsEvent(analyticsEvent);
var telemetryClient = _telemetryClientWrapper.TelemetryClient;
telemetryClient.TrackEvent(appInsightsEvent);
telemetryClient.Flush();
}
}
}
57 changes: 57 additions & 0 deletions IdeIntegration/Analytics/AppInsightsEventConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using Microsoft.ApplicationInsights.DataContracts;
using TechTalk.SpecFlow.IdeIntegration.Analytics;
using TechTalk.SpecFlow.IdeIntegration.Analytics.Events;

namespace TechTalk.SpecFlow.IdeIntegration.Analytics
{
public class AppInsightsEventConverter : IAppInsightsEventConverter
{
public EventTelemetry ConvertToAppInsightsEvent(IAnalyticsEvent analyticsEvent)
{
var eventTelemetry = new EventTelemetry(analyticsEvent.EventName)
{
Timestamp = analyticsEvent.UtcDate,
Properties =
{
{ "UserId", analyticsEvent.UserId },
{ "UtcDate", analyticsEvent.UtcDate.ToString("O") },
{ "Ide", analyticsEvent.Ide },
{ "IdeVersion", analyticsEvent.IdeVersion },
}
};

if (analyticsEvent is ExceptionAnalyticsEvent exceptionAnalyticsEvent)
{
eventTelemetry.Properties.Remove("UserId");
eventTelemetry.Properties.Add("ExceptionType", exceptionAnalyticsEvent.ExceptionType);
return eventTelemetry;
}
if (analyticsEvent is ExtensionInstalledAnalyticsEvent extensionInstalledAnalyticsEvent)
{
eventTelemetry.Properties.Add("ExtensionVersion", extensionInstalledAnalyticsEvent.ExtensionVersion);
}
if (analyticsEvent is ExtensionLoadedAnalyticsEvent extensionLoadedAnalyticsEvent)
{
eventTelemetry.Properties.Add("ExtensionVersion", extensionLoadedAnalyticsEvent.ExtensionVersion);
eventTelemetry.Properties.Add("ProjectTargetFramework", string.Join(";", extensionLoadedAnalyticsEvent.ProjectTargetFrameworks));
}
if (analyticsEvent is ExtensionUpgradedAnalyticsEvent extensionUpgradeAnalyticsEvent)
{
eventTelemetry.Properties.Add("ExtensionVersion", extensionUpgradeAnalyticsEvent.ExtensionVersion);
eventTelemetry.Properties.Add("OldExtensionVersion", extensionUpgradeAnalyticsEvent.OldExtensionVersion);
}
if (analyticsEvent is ProjectTemplateWizardCompletedAnalyticsEvent projectTemplateWizardCompleted)
{
eventTelemetry.Properties.Add("SelectedDotNetFramework", projectTemplateWizardCompleted.SelectedDotNetFramework);
eventTelemetry.Properties.Add("SelectedUnitTestFramework", projectTemplateWizardCompleted.SelectedUnitTestFramework);
}
if (analyticsEvent is NotificationAnalyticsEventBase notificationEvent)
{
eventTelemetry.Properties.Add("NotificationId", notificationEvent.NotificationId);
}

return eventTelemetry;
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace TechTalk.SpecFlow.IdeIntegration.Analytics
{
public static class AppInsightsInstrumentationKey
{
public const string Key = "<InstrumentationKeyGoesHere>";
}
}
24 changes: 24 additions & 0 deletions IdeIntegration/Analytics/ConsoleAnalyticsTransmitterSink.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;

namespace TechTalk.SpecFlow.IdeIntegration.Analytics
{
public class ConsoleAnalyticsTransmitterSink : IAnalyticsTransmitterSink
{
private readonly IEnableAnalyticsChecker _enableAnalyticsChecker;

public ConsoleAnalyticsTransmitterSink(IEnableAnalyticsChecker enableAnalyticsChecker)
{
_enableAnalyticsChecker = enableAnalyticsChecker;
}

public void TransmitEvent(IAnalyticsEvent analyticsEvent)
{
if (!_enableAnalyticsChecker.IsEnabled())
{
throw new InvalidOperationException("This method should not be called because analytics transmission is disabled.");
}

Console.WriteLine(analyticsEvent.ToString());
}
}
}
24 changes: 24 additions & 0 deletions IdeIntegration/Analytics/EnableAnalyticsChecker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;
using TechTalk.SpecFlow.IdeIntegration.Options;

namespace TechTalk.SpecFlow.IdeIntegration.Analytics
{
public class EnableAnalyticsChecker : IEnableAnalyticsChecker
{
private readonly IIntegrationOptionsProvider _integrationOptionsProvider;
private readonly IEnvironmentSpecFlowTelemetryChecker _environmentSpecFlowTelemetryChecker;

public EnableAnalyticsChecker(IIntegrationOptionsProvider integrationOptionsProvider, IEnvironmentSpecFlowTelemetryChecker environmentSpecFlowTelemetryChecker)
{
_integrationOptionsProvider = integrationOptionsProvider;
_environmentSpecFlowTelemetryChecker = environmentSpecFlowTelemetryChecker;
}

public bool IsEnabled()
{
var options = _integrationOptionsProvider.GetOptions();
var isSpecFlowTelemetryEnabled = _environmentSpecFlowTelemetryChecker.IsSpecFlowTelemetryEnabled();
return !options.OptOutDataCollection && isSpecFlowTelemetryEnabled;
}
}
}
15 changes: 15 additions & 0 deletions IdeIntegration/Analytics/EnvironmentSpecFlowTelemetryChecker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;

namespace TechTalk.SpecFlow.IdeIntegration.Analytics
{
public class EnvironmentSpecFlowTelemetryChecker : IEnvironmentSpecFlowTelemetryChecker
{
public const string SpecFlowTelemetryEnvironmentVariable = "SPECFLOW_TELEMETRY_ENABLED";

public bool IsSpecFlowTelemetryEnabled()
{
var specFlowTelemetry = Environment.GetEnvironmentVariable(SpecFlowTelemetryEnvironmentVariable);
return specFlowTelemetry == null || specFlowTelemetry.Equals("1");
}
}
}
4 changes: 3 additions & 1 deletion IdeIntegration/Analytics/Events/AnalyticsEventBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@ namespace TechTalk.SpecFlow.IdeIntegration.Analytics.Events
{
public abstract class AnalyticsEventBase : IAnalyticsEvent
{
protected AnalyticsEventBase(string ide, DateTime utcDate, string userId)
protected AnalyticsEventBase(string ide, string ideVersion, DateTime utcDate, string userId)
{
Ide = ide;
IdeVersion = ideVersion;
UtcDate = utcDate;
UserId = userId;
}

public abstract string EventName { get; }
public string Ide { get; }
public string IdeVersion { get; }
public DateTime UtcDate { get; }
public string UserId { get; }
}
Expand Down
4 changes: 3 additions & 1 deletion IdeIntegration/Analytics/Events/ExceptionAnalyticsEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@ namespace TechTalk.SpecFlow.IdeIntegration.Analytics.Events
{
public class ExceptionAnalyticsEvent : IAnalyticsEvent
{
public ExceptionAnalyticsEvent(string ide, string exceptionType, DateTime utcDate)
public ExceptionAnalyticsEvent(string ide, string ideVersion, string exceptionType, DateTime utcDate)
{
Ide = ide;
IdeVersion = ideVersion;
ExceptionType = exceptionType;
UtcDate = utcDate;
UserId = null;
}

public string EventName => "Visual Studio Extension Exception";
public string Ide { get; }
public string IdeVersion { get; }
public DateTime UtcDate { get; }
public string UserId { get; }
public string ExceptionType { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@ namespace TechTalk.SpecFlow.IdeIntegration.Analytics.Events
{
public class ExtensionInstalledAnalyticsEvent : AnalyticsEventBase
{
public ExtensionInstalledAnalyticsEvent(string ide, DateTime utcDate, string userId, string ideVersion, string extensionVersion) : base(ide, utcDate, userId)
public ExtensionInstalledAnalyticsEvent(string ide, DateTime utcDate, string userId, string ideVersion, string extensionVersion) : base(ide, ideVersion, utcDate, userId)
{
IdeVersion = ideVersion;
ExtensionVersion = extensionVersion;
}

public override string EventName => "Extension installed";

public string IdeVersion { get; }

public string ExtensionVersion { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,14 @@ namespace TechTalk.SpecFlow.IdeIntegration.Analytics.Events
{
public class ExtensionLoadedAnalyticsEvent : AnalyticsEventBase
{
public ExtensionLoadedAnalyticsEvent(string ide, DateTime utcDate, string userId, string ideVersion, string extensionVersion, IEnumerable<string> projectTargetFrameworks) : base(ide, utcDate, userId)
public ExtensionLoadedAnalyticsEvent(string ide, DateTime utcDate, string userId, string ideVersion, string extensionVersion, IEnumerable<string> projectTargetFrameworks) : base(ide, ideVersion, utcDate, userId)
{
IdeVersion = ideVersion;
ExtensionVersion = extensionVersion;
ProjectTargetFrameworks = projectTargetFrameworks.ToArray();
}

public override string EventName => "Extension loaded";

public string IdeVersion { get; }

public string ExtensionVersion { get; }
public IReadOnlyList<string> ProjectTargetFrameworks { get; }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace TechTalk.SpecFlow.IdeIntegration.Analytics.Events
{
public class ExtensionUpgradedAnalyticsEvent : AnalyticsEventBase
{
public ExtensionUpgradedAnalyticsEvent(string ide, DateTime utcDate, string userId, string oldExtensionVersion, string extensionVersion) : base(ide, utcDate, userId)
public ExtensionUpgradedAnalyticsEvent(string ide, DateTime utcDate, string userId, string ideVersion, string oldExtensionVersion, string extensionVersion) : base(ide, ideVersion, utcDate, userId)
{
OldExtensionVersion = oldExtensionVersion;
ExtensionVersion = extensionVersion;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ public class ExtensionUsageAnalyticsEvent : AnalyticsEventBase
{
private readonly int _daysUsage;

public ExtensionUsageAnalyticsEvent(string ide, DateTime utcDate, string userId, int daysUsage) : base(ide, utcDate, userId)
public ExtensionUsageAnalyticsEvent(string ide, DateTime utcDate, string userId, string ideVersion, int daysUsage) : base(ide, ideVersion, utcDate, userId)
{
_daysUsage = daysUsage;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ public abstract class NotificationAnalyticsEventBase : AnalyticsEventBase
{
public string NotificationId { get; }

protected NotificationAnalyticsEventBase(string ide, DateTime utcDate, string userId, string notificationId) : base(ide, utcDate, userId)
protected NotificationAnalyticsEventBase(string ide, DateTime utcDate, string ideVersion, string userId, string notificationId) : base(ide, ideVersion, utcDate, userId)
{
NotificationId = notificationId;
}
}

public class NotificationShownAnalyticsEvent : NotificationAnalyticsEventBase
{
public NotificationShownAnalyticsEvent(string ide, DateTime utcDate, string userId, string notificationId) : base(ide, utcDate, userId, notificationId)
public NotificationShownAnalyticsEvent(string ide, DateTime utcDate, string ideVersion, string userId, string notificationId) : base(ide, utcDate, ideVersion, userId, notificationId)
{
}

Expand All @@ -23,7 +23,7 @@ public NotificationShownAnalyticsEvent(string ide, DateTime utcDate, string user

public class NotificationLinkOpenedAnalyticsEvent : NotificationAnalyticsEventBase
{
public NotificationLinkOpenedAnalyticsEvent(string ide, DateTime utcDate, string userId, string notificationId) : base(ide, utcDate, userId, notificationId)
public NotificationLinkOpenedAnalyticsEvent(string ide, DateTime utcDate, string ideVersion, string userId, string notificationId) : base(ide, utcDate, ideVersion, userId, notificationId)
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace TechTalk.SpecFlow.IdeIntegration.Analytics.Events
{
public class ProjectTemplateWizardCompletedAnalyticsEvent : AnalyticsEventBase
{
public ProjectTemplateWizardCompletedAnalyticsEvent(string ide, DateTime utcDate, string userId, string selectedDotNetFramework, string selectedUnitTestFramework) : base(ide, utcDate, userId)
public ProjectTemplateWizardCompletedAnalyticsEvent(string ide, DateTime utcDate, string userId, string ideVersion, string selectedDotNetFramework, string selectedUnitTestFramework) : base(ide, ideVersion, utcDate, userId)
{
SelectedDotNetFramework = selectedDotNetFramework;
SelectedUnitTestFramework = selectedUnitTestFramework;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace TechTalk.SpecFlow.IdeIntegration.Analytics.Events
{
public class ProjectTemplateWizardStartedAnalyticsEvent : AnalyticsEventBase
{
public ProjectTemplateWizardStartedAnalyticsEvent(string ide, DateTime utcDate, string userId) : base(ide, utcDate, userId)
public ProjectTemplateWizardStartedAnalyticsEvent(string ide, DateTime utcDate, string userId, string ideVersion) : base(ide, ideVersion, utcDate, userId)
{
}

Expand Down
Loading