danielpalme / ReportGenerator

ReportGenerator converts coverage reports generated by coverlet, OpenCover, dotCover, Visual Studio, NCover, Cobertura, JaCoCo, Clover, gcov or lcov into human readable reports in various formats.

Home Page:https://reportgenerator.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Projects with DebugType "Portable" experience internal server 500 error while reading source files.

IMDiSc opened this issue · comments

TLDR;
Applying the fix from #501 (see here) solves the issue, but I'd like to understand why.

UPDATE:
The fix from #501 does not solve everything.
While it does get rid of the errors in the build log that it can't access the files, the actual file contents shown are still HTML page:
image

While I was typing out this issue, I was continually testing and debugging the issue at hand.
So I eventually figured out the issue, but I'd still like to know why exactly it doesn't work.

The issue:

I noticed the coverage reports of some of my pipelines weren't working as expected.
It wouldn't show the file contents of the file, instead it showed HTML code.
After looking at the logs of that run, i noticed alot of these:
Error during reading file 'https://dev.azure.com/.../items?api-version=1.0&versionType=commit&version=437a707e7c785092f2bc86876e60a4ba3d6f5c61&path=MyFile.cs': Response status code does not indicate success: 500 (Internal Server Error).

I then looked at another build pipeline and sure enough, the coverage report there was working as expected.

The project that failed was:

  • A .NET 7 class library, being packaged as a NuGet package + symbol package (snupkg). Along with a xUnit test project also in .NET 7

The project that succeeded was:

  • A .net framework 4.8 console project, along with a xUnit test project also in .net framework 4.8

Both project had SourceLink enabled:

<PropertyGroup Condition="'$(TF_BUILD)' == 'true'">
    <ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
    <EmbedUntrackedSources>true</EmbedUntrackedSources>
</PropertyGroup>

<ItemGroup>
    <PackageReference Include="Microsoft.SourceLink.AzureRepos.Git" Version="1.1.1" PrivateAssets="All" />
</ItemGroup>

When looking at the coverage report of the project that failed, it would show an URL in the Information block for the File row like this:
https://dev.azure.com/.../items?api-version=1.0&versionType=commit&version=437a707e7c785092f2bc86876e60a4ba3d6f5c61&path=path/to/MyFile.cs
When comparing that with the coverage report of the project that succeeded, there it showed something along the lines of /_/path/to/MyFile.cs

The only difference I could find between the two, configuration wise, was that the project that failed had set <DebugType>Portable</DebugType> (as recommended by MSFT, per the docs for symbol packages)
The other one had set <DebugType>pdbonly</DebugType>

Once I changed the value of DebugType to pdbonly on the project that failed, the coverage report worked as expected.
It would no longer show URLs for files and instead show the path'ish value as in the other project.

Then I learned that since C6.0, using pdbonly is the same as using full, which I always thought was bad to have for release builds.

So while the fix provided in #501 works, I'm a bit hesitant to implement it due to the fact that a PAT will expire after a year max.
The agent running the task is authenticated with Azure, so why can't reportgenerator re-use / work within that context?

Or can't there be a way to "translate" the URLs to local paths? In my case (and probably in many others) the sources will be available locally anyway...

So if anyone has any thoughts or suggestions, i'd be happy to hear it

One thing that comes to mind would be the following:

Instead of creating a PAT, base64 encode that with : in front of it and passing that to the reportgenerator task,

why not do the same, but use the predefined $(System.AccessToken) variable?

https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml#systemaccesstoken

Updated my OP
Adding the custom settings with the header does solve the errors about not being able to access the file, however when I look at the report, I still see HTML code for the Azure DevOps signin page.

I also went ahead and tried the following combinations:

  • Use Authorization=Bearer $(System.AccessToken)
    This also got rid of the errors, but still the same issue with the HTML being shown
  • Use Authorization=Basic $(System.AccessToken)
    Same result as above, weirdly. I'd expect a error here about not being able to authorize
  • Added a powershell task right before the reportgenetor one, which would base64 encode my PAT (stored in Library group) and then publish the encoded value as a variable, which i'd then use in the reportgenerator task.

Just found #574, which is exactly what I'm experiencing but there the custom header thing solved it

Just had a look at the XML of the coverage.cobertura.xml file on the build server.

This is such a class element:

<class name="MyFile" filename="https://dev.azure.com/<org>/<project>/_apis/git/repositories/<repo>/items?api-version=1.0&amp;versionType=commit&amp;version=cd08f3ea70b6f2af6759105e6354412912f4607a&amp;path=/path/to/MyFile.cs" line-rate="0" branch-rate="1" complexity="1">
	<methods>
		<method name="Slice" signature="(T[],System.Int32,System.Int32)" line-rate="0" branch-rate="1" complexity="1">
			<lines>
				<line number="9" hits="0" branch="false"/>
				<line number="10" hits="0" branch="false"/>
				<line number="11" hits="0" branch="false"/>
			</lines>
		</method>
	</methods>
	<lines>
		<line number="9" hits="0" branch="false"/>
		<line number="10" hits="0" branch="false"/>
		<line number="11" hits="0" branch="false"/>
	</lines>
</class>

When I manually visit the URL, I expected the file to be shown.
Instead, I got a JSON response:

{
    "count": 1,
    "value": [
        {
            "objectId": "ff0f119466f3a659fccfbc3c55da2a7f010d688f",
            "gitObjectType": "tree",
            "commitId": "437a707e7c785092f2bc86876e60a4ba3d6f5c61",
            "path": "/",
            "isFolder": true,
            "url": "https://dev.azure.com/<org>/e02f8955-9af5-4c0b-b176-6d84d4bf262f/_apis/git/repositories/5b4d0245-81fb-49de-b9fd-c3a6c29010da/items?path=%2F&versionType=Branch&versionOptions=None"
        }
    ]
}

Replaced sensitive data with placeholders in the URLs ofcourse

If I however manually fix the URL from
https://dev.azure.com/<org>/<proj>/_apis/git/repositories/<repo>/items?api-version=1.0&amp;versionType=commit&amp;version=cd08f3ea70b6f2af6759105e6354412912f4607a&amp;path=/Path/To/MyFile.cs
to
https://dev.azure.com/<org>/<proj>/_apis/git/repositories/<repo>/items?api-version=1.0&versionType=commit&version=cd08f3ea70b6f2af6759105e6354412912f4607a&path=/Path/To/MyFile.cs

I do get back the file contents.

So this might be an issue in coverlet / coberatura then?

After going through this file:

if (path.StartsWith("http://") || path.StartsWith("https://"))

I'd figured I give clearing that cache folder a go.

And it seems to be working correctly now, so I'll go ahead and close this for now.

My build pipelines heavily relies on templates from another repository, in which I was making most changes. So that's probably why it would grab the cached items, because the commit hash of the actual repo being built hadn't changed.