Skip to content
This repository has been archived by the owner on Aug 30, 2023. It is now read-only.

feat: Returns better version data than default API #248

Merged
merged 3 commits into from
May 5, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
14 changes: 8 additions & 6 deletions src/app/SharpRaven/Data/Context/Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ public class Runtime
/// </remarks>
[JsonProperty(PropertyName = "raw_description", NullValueHandling = NullValueHandling.Ignore)]
public string RawDescription { get; set; }
/// <summary>
/// An optional build number
/// </summary>
/// <see href="https://docs.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed"/>
[JsonProperty(PropertyName = "build", NullValueHandling = NullValueHandling.Ignore)]
public string Build { get; set; }

/// <summary>
/// Clones this instance
Expand All @@ -73,6 +79,7 @@ internal Runtime Clone()
{
Name = this.Name,
Version = this.Version,
Build = this.Build,
RawDescription = this.RawDescription
};
}
Expand All @@ -85,12 +92,7 @@ public static Runtime Create()
{
try
{
var runtime = new Runtime
{
RawDescription = RuntimeInfoHelper.GetRuntimeVersion()
};

return runtime;
return RuntimeInfoHelper.GetRuntime();
}
catch (Exception e)
{
Expand Down
14 changes: 14 additions & 0 deletions src/app/SharpRaven/Data/Context/RuntimeExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace SharpRaven.Data.Context
{
internal static class RuntimeExtensions
{
public static bool IsNetFx(this Runtime runtime) => runtime.IsRuntime(".NET Framework");
public static bool IsNetCore(this Runtime runtime) => runtime.IsRuntime(".NET Core");

private static bool IsRuntime(this Runtime runtime, string runtimeName)
{
return runtime?.Name?.StartsWith(runtimeName) == true
|| runtime?.RawDescription?.StartsWith(runtimeName) == true;
}
}
}
31 changes: 21 additions & 10 deletions src/app/SharpRaven/SharpRaven.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,37 @@

<Import Project="..\..\CommonConfigurations.targets" />

<ItemGroup Condition="'$(TargetFramework)' == 'net35' or '$(TargetFramework)' == 'net40' or '$(TargetFramework)' == 'net45'">
<ItemGroup Condition="'$(TargetFramework)' == 'net35'">
<Reference Include="System" />
<Reference Include="System.Web" />
<Reference Include="System.Configuration" />
<PackageReference Include="Newtonsoft.Json" Version="6.0.8" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net35'">
<Reference Include="System.Web" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net40' or '$(TargetFramework)' == 'net45'">
<PropertyGroup Condition="'$(TargetFramework)' == 'net35'">
<DefineConstants>NETFX;$(AdditionalConstants)</DefineConstants>
</PropertyGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net40'">
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="Microsoft.CSharp" />
<PackageReference Include="Newtonsoft.Json" Version="6.0.8" />
</ItemGroup>

<PropertyGroup Condition="'$(TargetFramework)' == 'net40'">
<DefineConstants>NETFX;$(AdditionalConstants)</DefineConstants>
</PropertyGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net45'">
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Net.Http" />
<Reference Include="Microsoft.CSharp" />
<PackageReference Include="Newtonsoft.Json" Version="6.0.8" />
<PackageReference Include="System.Runtime.InteropServices.RuntimeInformation" Version="4.3.0" />
</ItemGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'net45'">
<DefineConstants>HAS_RUNTIME_INFORMATION;$(AdditionalConstants)</DefineConstants>
<DefineConstants>NETFX;HAS_RUNTIME_INFORMATION;NET45PLUS_REGISTRY_VERSION;$(AdditionalConstants)</DefineConstants>
</PropertyGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net471'">
Expand All @@ -51,7 +62,7 @@
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
</ItemGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'net471'">
<DefineConstants>HAS_RUNTIME_INFORMATION;$(AdditionalConstants)</DefineConstants>
<DefineConstants>NETFX;HAS_RUNTIME_INFORMATION;NET45PLUS_REGISTRY_VERSION;$(AdditionalConstants)</DefineConstants>
</PropertyGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
Expand Down
82 changes: 66 additions & 16 deletions src/app/SharpRaven/Utilities/RuntimeInfoHelper.cs
Original file line number Diff line number Diff line change
@@ -1,46 +1,96 @@
using System;
using System.Reflection;

using SharpRaven.Data.Context;
#if HAS_RUNTIME_INFORMATION
using System.Runtime.InteropServices;
#endif
#if NET45PLUS_REGISTRY_VERSION
using Microsoft.Win32;
#endif

namespace SharpRaven.Utilities
{
internal static class RuntimeInfoHelper
{
public static string GetRuntimeVersion()
public static Runtime GetRuntime()
{
#if HAS_RUNTIME_INFORMATION
#if HAS_RUNTIME_INFORMATION // .NET Core 2+, .NET Framework 4.5+
// Prefered API: netstandard2.0 and vNext
// https://github.com/dotnet/corefx/blob/master/src/System.Runtime.InteropServices.RuntimeInformation/src/System/Runtime/InteropServices/RuntimeInformation/RuntimeInformation.cs
// e.g: .NET Framework 4.7.2633.0, .NET Native, WebAssembly
var version = RuntimeInformation.FrameworkDescription;
var runtime = new Runtime
{
RawDescription = RuntimeInformation.FrameworkDescription
};
#else
var mono = GetFromMono();
var version = mono
var runtime = GetFromMono();
runtime = runtime
// Environment.Version: NET Framework 4, 4.5, 4.5.1, 4.5.2 = 4.0.30319.xxxxx
// .NET Framework 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1 = 4.0.30319.42000
// Not recommended on NET45+
?? $".NET Framework {Environment.Version}";
?? new Runtime
{
Name = ".NET Framework",
Version = Environment.Version.ToString()
};
#endif
return version;

#if NET45PLUS_REGISTRY_VERSION // .NET Framework 4.5 and later
if (runtime.IsNetFx())
{
runtime.Build = Get45PlusLatestInstallationFromRegistry()?.ToString();
}
#endif

#if !NETFX // Non .NET Framework (i.e: netstandard, netcoreapp)
if (runtime.IsNetCore())
{
// RuntimeInformation.FrameworkDescription returns 4.6 on .NET Core 2.0 which is counter intuitive
var assembly = typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly;
var assemblyPath = assembly.CodeBase.Split(new[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries);
var netCoreAppIndex = Array.IndexOf(assemblyPath, "Microsoft.NETCore.App");
if (netCoreAppIndex > 0 && netCoreAppIndex < assemblyPath.Length - 2)
{
runtime.Name = ".NET Core";
runtime.Version = assemblyPath[netCoreAppIndex + 1];
}
}
#endif
return runtime;
}

private static string GetFromMono()
private static Runtime GetFromMono()
{
// The implementation of Mono to RuntimeInformation:
// https://github.com/mono/mono/blob/90b49aa3aebb594e0409341f9dca63b74f9df52e/mcs/class/corlib/System.Runtime.InteropServices.RuntimeInformation/RuntimeInformation.cs
// e.g; Mono 5.10.0 (Visual Studio built mono)
var monoVersion = Type.GetType("Mono.Runtime", false)
?.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static)
?.Invoke(null, null) as string;
return Type.GetType("Mono.Runtime", false)
?.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static)
?.Invoke(null, null)
is string monoVersion
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The line breaking here is a bit funky. 😄 Perhaps breaking the expression up a bit would make it more readable as well?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, did reformat a bit to improve readability.
I do believe it might be about getting used to pattern matching syntax a bit.

? new Runtime
{
// Send complete (raw) and let Sentry parse it. UI can display short version but details are not lost
// e.g; Mono 5.10.0 (Visual Studio built mono)
// e.g: Mono 5.10.1.47 (tarball Tue Apr 17 09:23:16 UTC 2018)
RawDescription = "Mono " + monoVersion
}
: null;
}

if (monoVersion != null)
#if NET45PLUS_REGISTRY_VERSION
// https://docs.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed#to-find-net-framework-versions-by-querying-the-registry-in-code-net-framework-45-and-later
internal static int? Get45PlusLatestInstallationFromRegistry()
{
const string subkey = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\";

using (var ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(subkey))
{
monoVersion = "Mono " + monoVersion;
return int.TryParse(ndpKey?.GetValue("Release")?.ToString(), out var releaseId)
? releaseId
: (int?)null;
}

return monoVersion;
}
#endif
}
}
13 changes: 8 additions & 5 deletions src/tests/SharpRaven.UnitTests/Data/Context/RuntimeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@ namespace SharpRaven.UnitTests.Data.Context
public class RuntimeTests
{
[Test]
public void Create_RawDescription_NotNullAndAsHelper()
public void Create_Runtime_NotNullAndAsHelper()
{
var runtime = Runtime.Create();
var actual = Runtime.Create();

var expected = RuntimeInfoHelper.GetRuntimeVersion();
Assert.NotNull(runtime.RawDescription);
Assert.AreEqual(expected, runtime.RawDescription);
var expected = RuntimeInfoHelper.GetRuntime();
Assert.NotNull(actual);
Assert.AreEqual(expected.Build, actual.Build);
Assert.AreEqual(expected.Version, actual.Version);
Assert.AreEqual(expected.Name, actual.Name);
Assert.AreEqual(expected.RawDescription, actual.RawDescription);
}

[Test]
Expand Down
37 changes: 23 additions & 14 deletions src/tests/SharpRaven.UnitTests/SharpRaven.UnitTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,34 +12,43 @@
<ProjectReference Include="..\..\app\SharpRaven\SharpRaven.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="NSubstitute" Version="1.8.0.0" />
<PackageReference Include="NUnit" Version="2.6.4" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net471'">
<Reference Include="System.Web" />
<Reference Include="System.Configuration" />
<Reference Include="Microsoft.CSharp" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
</ItemGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'net471'">
<DefineConstants>NET45PLUS_REGISTRY_VERSION;HAS_RUNTIME_INFORMATION;$(AdditionalConstants)</DefineConstants>
</PropertyGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net35' or '$(TargetFramework)' == 'net40' or '$(TargetFramework)' == 'net45'">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The references are not required on .NET 3.5 or 4.0?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just moved it to their own blocks as it was tricky to follow what target gets what

<ItemGroup Condition="'$(TargetFramework)' == 'net45'">
<Reference Include="System" />
<Reference Include="System.Web" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net40' or '$(TargetFramework)' == 'net45'">
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.VisualBasic" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' != 'net35' and '$(TargetFramework)' != 'net40'">
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
</ItemGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'net45'">
<DefineConstants>NET45PLUS_REGISTRY_VERSION;HAS_RUNTIME_INFORMATION;$(AdditionalConstants)</DefineConstants>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="NSubstitute" Version="1.8.0.0" />
<PackageReference Include="NUnit" Version="2.6.4" />
<ItemGroup Condition="'$(TargetFramework)' == 'net40'">
<Reference Include="System" />
<Reference Include="System.Web" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.VisualBasic" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net35'">
<Reference Include="System" />
<Reference Include="System.Web" />
</ItemGroup>

<PropertyGroup Condition="'$(TargetFramework)' == 'net471' OR '$(TargetFramework)' == 'net45'">
<DefineConstants>HAS_RUNTIME_INFORMATION;$(AdditionalConstants)</DefineConstants>
</PropertyGroup>

<ItemGroup>
<Compile Include="..\..\CommonAssemblyInfo.cs" Link="Properties\CommonAssemblyInfo.cs" />
Expand Down
23 changes: 23 additions & 0 deletions src/tests/SharpRaven.UnitTests/Utilities/RuntimeInfoHelperTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using NUnit.Framework;
using SharpRaven.Utilities;

namespace SharpRaven.UnitTests.Utilities
{
public class RuntimeInfoHelperTests
{
[Test]
public void GetRuntime_NotNull()
{
var runtime = RuntimeInfoHelper.GetRuntime();
Assert.That(runtime, Is.Not.Null);
}
#if NET45PLUS_REGISTRY_VERSION
[Test]
public void Get45PlusLatestInstallationFromRegistry_FindsReleaseKey()
{
var version = RuntimeInfoHelper.Get45PlusLatestInstallationFromRegistry();
Assert.That(version, Is.Not.Null);
}
#endif
}
}