Search code examples
c#.netmsbuildreportgeneratorcoverlet

Running a Target only once per solution


I'm trying to find a way to run a specific target only once per solution after tests are done.

I have a solution with multiple test projects. Each has integration with coverlet.msbuild, hence they each produce a coverage report (opencover) file in a designated folder.

What I want to achieve is run another target, namely ReportGenerator, but only after all the tests are done and all the coverage report files are created. I've successfully created those report after the VSTest target. But that means I generate the report multiple times in a single run, because each testing project is running a VSTest target separately.

this is my latest attempt

<Project>
    <PropertyGroup>
        <CollectCoverage>true</CollectCoverage>
        <CoverletOutput>../../coverage/opencover/$(MSBuildProjectName).xml</CoverletOutput>
        <CoverletOutputFormat>opencover</CoverletOutputFormat>        
    </PropertyGroup>
    <ItemGroup>
        <PackageReference Include="coverlet.collector" Version="3.1.0">
            <PrivateAssets>all</PrivateAssets>
            <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
        </PackageReference>
        <PackageReference Include="coverlet.msbuild" Version="3.1.0">
            <PrivateAssets>all</PrivateAssets>
            <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
        </PackageReference>
        <PackageReference Include="ReportGenerator" Version="5.0.4" />
    </ItemGroup>
    
    <Target Name="GenerateHtmlCoverageReport" AfterTargets="GenerateCoverageResultAfterTest">
        <ReportGenerator
            ReportFiles="@(CoverletReport)"
            TargetDirectory="../../coverage/html-coverage-report"
            ProjectDirectory="$(MSBuildProjectDirectory)"
            ClassFilters="-*OrleansGeneratedCode*"
            HistoryDirectory="../../coverage/history"
            ReportTypes="HTML"
            VerbosityLevel="Verbose" />
    </Target>
    
</Project>

Note: this is a separate props file included in the Directory.Build.props that is used by all test projects, just to avoid duplication.

Any ideas?


Solution

  • After some research I've found that it is possible to run specific targets only once per solution by customizing the build process as described in the microsoft documentation

    the trick was to introduce a targets file called after.<solution name>.sln.targets near the solution file.

    in my case it was:

    <Project>
     <Target Name="GenerateHtmlCoverageReport" AfterTargets="VSTest">
      <Exec Command="ReportGenerator -reports:./tests/coverage/projects/*/*.xml -targetdir:./tests/coverage/report/ -reporttypes:Html_Dark -sourcedirs:./src/ -historydir:./tests/coverage/history" />
     </Target>
    </Project>
    

    which ran this target after the VSTest target was run, which is only once per solution.