getsentry / sentry-dotnet

Sentry SDK for .NET
https://docs.sentry.io/platforms/dotnet
MIT License
579 stars 206 forks source link

`SentryCreateRelease` not using `AssemblyInformationalVersion` from `Nerdbank.GitVersioning` #3536

Open meenzen opened 4 weeks ago

meenzen commented 4 weeks ago

Package

Sentry.AspNetCore

.NET Flavor

.NET

.NET Version

8.0.400

OS

Linux

SDK Version

4.10.0

Self-Hosted Sentry Version

24.7.1

Steps to Reproduce

  1. Have an existing project that uses Nerdbank.GitVersioning
  2. Enable the new features by adding these properties to the project config:

    <SentryCreateRelease>true</SentryCreateRelease>
    <SentrySetCommits>true</SentrySetCommits>
  3. Build the new release

Nerdbank.GitVersioning adds code at compile time:

#pragma warning disable CA2243

[assembly: System.Reflection.AssemblyVersionAttribute("2.2.0.0")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("2.2")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("2.2.0-alpha.1231+d4b08efa99")]
#if NETSTANDARD || NETFRAMEWORK || NETCOREAPP
[System.CodeDom.Compiler.GeneratedCode("Nerdbank.GitVersioning.Tasks","3.6.141.978")]
#endif
#if NET40_OR_GREATER || NETCOREAPP2_0_OR_GREATER || NETSTANDARD2_0_OR_GREATER
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
#endif
internal static partial class ThisAssembly {
    internal const string AssemblyConfiguration = "Debug";
    internal const string AssemblyFileVersion = "2.2";
    internal const string AssemblyInformationalVersion = "2.2.0-alpha.1231+d4b08efa99";
    internal const string AssemblyName = "ExampleApp";
    internal const string AssemblyTitle = "ExampleApp";
    internal const string AssemblyVersion = "2.2.0.0";
    internal static readonly System.DateTime GitCommitDate = new System.DateTime(638593071050000000L, System.DateTimeKind.Utc);
    internal const string GitCommitId = "d4b08efa99564ae8a294e3f8888a1292f06adab7";
    internal const bool IsPrerelease = true;
    internal const bool IsPublicRelease = true;
    internal const string RootNamespace = "ExampleApp";
}

Expected Result

The version from the AssemblyInformationalVersionAttribute is being used to create the release

The following code suggests this should work: https://github.com/getsentry/sentry-dotnet/pull/3462/files#diff-14707e966a1fc6c249c6ab6fb17b0aac9349add0d80942b4710d96f7af1f0217R278

Actual Result

A release using the AssemblyVersion is created:

  Getting Sentry Release...
  Sentry Release: ExampleApp@2.2.0.0
  Creating Sentry Release: ExampleApp@2.2.0.0
  Created release ExampleApp@2.2.0.0
  Setting Sentry commits
  +------------------------------+--------------+
  | Repository                   | Revision     |
  +------------------------------+--------------+
  | ExampleApp                   | 428ce4f05351 |
  +------------------------------+--------------+

I have not tested this without Nerdbank.GitVersioning but something is obviously wrong here.

jamescrosswell commented 4 weeks ago

Hi @meenzen , can you run your dotnet build with detailed logging so that we can see what gets logged by the code that you linked to?

-v, --verbosity <LEVEL>              Set the MSBuild verbosity level. Allowed values are q[uiet], m[inimal], 
                                       n[ormal], d[etailed], and diag[nostic].

In particular, it'd be good check if an exception is raised when trying to read the AssemblyInformationalVersionAttribute. I think the only thing that might cause that is an AmbiguousMatchException from the Attribute.GetCustomAttribute but worth ruling this out.

Otherwise, my best guess is that maybe NerdBank is applying the version information to a different assembly to the one that the Sentry build task is reading? Again, using detailed logging above would help determine that.

meenzen commented 4 weeks ago

Reading the attribute does indeed fail:

Getting assembly name...
Assembly name: ExampleApp
Reading AssemblyInformationalVersionAttribute...
Failed to read informational version attribute
Version: 2.2.0.0
Compiling release information...

Grabbing the attributes during runtime yields exactly one result as expected:

typeof(Program).Assembly.GetCustomAttributes<AssemblyInformationalVersionAttribute>();
jamescrosswell commented 3 weeks ago

Hm, are you able to put together a minimal reproducible example that we can look at? I'm not familiar with nerdbank and it looks like there are various ways you can integrate this.

bitsandfoxes commented 2 weeks ago

Hey @meenzen, could you help us our with a minimal repro? We're really stuck on this one without it.

meenzen commented 2 weeks ago

I've managed to reproduce this now and it's really weird. The issue somehow only happens when the Microsoft.Identity.Web NuGet package is installed.

Reproduction: https://github.com/meenzen/sentry-create-release-issue

jamescrosswell commented 1 week ago

I've managed to reproduce this now and it's really weird. The issue somehow only happens when the Microsoft.Identity.Web NuGet package is installed.

Thanks @meenzen - that repro works for me too.

As you say, it's very weird. I added this to your Program.cs and at Runtime the attribute is always available (and the full informational version is reported):

var assembly = typeof(Program).Assembly;

try
{
    var assemblyName = assembly.GetName();
    Console.WriteLine($"Assembly Name: {assemblyName.Name}");
    Console.WriteLine($"Assembly Version: {assemblyName.Version}");
}
catch 
{
    Console.WriteLine("Failed to read Assembly Name");
}

try
{
    var infoVersionAttribute = assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>();
    Console.WriteLine($"Informational Version: {infoVersionAttribute?.InformationalVersion}");
}
catch
{
    Console.WriteLine("Failed to read Informational Version");
}

So this is build time only problem.

As you say, if the reference to Microsoft.Identity.Web is commented out, the build task works as well.

If Microsoft.Identity.Web is included in the project and I run dotnet build -c Release -v d, this is what gets logged by the build task:

       Task "SentryGetApplicationVersion"
         Loading assembly: obj/Release/net8.0/Sentry.Bazinga.ConsoleApp.dll
         Getting assembly name...
         Assembly name: 
         Reading AssemblyInformationalVersionAttribute...
         Failed to read informational version attribute
         Version: 67.131.1991.99
         Compiling release information...
       Done executing task "SentryGetApplicationVersion".

I figured it might have something to do with the order/timing of some task(s) that get run when including Microsoft.Identity.Web and the Sentry build task... so, as an experiment, I changed the Sentry build task to be AfterTargets="AfterBuild" rather than AfterTargets="DispatchToInnerBuilds;AfterBuild"... and this does have some impact:

       Task "SentryGetApplicationVersion"
         Loading assembly: obj/Release/net8.0/Sentry.Bazinga.ConsoleApp.dll
         Getting assembly name...
         Assembly name: Sentry.Bazinga.ConsoleApp
         Reading AssemblyInformationalVersionAttribute...
         Failed to read informational version attribute
         Version: 2.2.0.0
         Compiling release information...
       Done executing task "SentryGetApplicationVersion".

So when the build task is delayed, it's able to resolve the Assembly name and version properly, but still not able to get the AssemblyInformationalVersionAttribute.

I think there's something funky going on with transitive build targets in Microsoft.Identity.Web or one of it's dependencies...

jamescrosswell commented 1 week ago

I can't see what's causing this. None of the nuget packages have any transitive build targets that look relevant.

jamescrosswell commented 1 week ago

@meenzen as a workaround, you could set the SENTRY_RELEASE environment variable manually before running the build... which the Sentry build task would pick up (instead of trying to read the release information from the Assembly).