Skip to content

coverlet.console with exit codes (ExitCodes.cs) #1746

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

Open
wants to merge 11 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
10 changes: 5 additions & 5 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<MicrosoftCodeAnalysisVersion>4.12.0</MicrosoftCodeAnalysisVersion>
<!-- Test Platform, .NET Test SDK and Object Model -->
<MicrosoftNETTestSdkVersion>17.13.0</MicrosoftNETTestSdkVersion>
<NugetPackageVersion>6.13.2</NugetPackageVersion>
<NugetPackageVersion>6.14.0</NugetPackageVersion>
<XunitV3Version>2.0.0</XunitV3Version>
<XunitRunnerVisualstudioVersion>3.0.2</XunitRunnerVisualstudioVersion>
</PropertyGroup>
Expand Down Expand Up @@ -54,18 +54,18 @@
<PackageVersion Include="Tmds.ExecFunction" Version="0.8.0" />
<PackageVersion Include="xunit.v3" Version="$(XunitV3Version)" />
<PackageVersion Include="xunit.runner.visualstudio" Version="$(XunitRunnerVisualstudioVersion)" />
<PackageVersion Include="System.Buffers" Version="4.6.0" />
<PackageVersion Include="System.Buffers" Version="4.6.1" />
<PackageVersion Include="System.Collections.Immutable" Version="8.0.0" />
<PackageVersion Include="System.Configuration.ConfigurationManager" Version="8.0.0" />
<PackageVersion Include="System.Linq.Async" Version="6.0.1" />
<PackageVersion Include="System.Memory" Version="4.6.0" />
<PackageVersion Include="System.Memory" Version="4.6.3" />
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
<PackageVersion Include="System.Reflection.Metadata" Version="8.0.1" />
<PackageVersion Include="System.Runtime.CompilerServices.Unsafe" Version="6.1.0" />
<PackageVersion Include="System.Runtime.CompilerServices.Unsafe" Version="6.1.2" />
<PackageVersion Include="System.Security.Cryptography.Pkcs" Version="6.0.5" />
<PackageVersion Include="System.Text.Encoding.CodePages" Version="8.0.0" />
<PackageVersion Include="System.Text.Json" Version="8.0.5" />
<PackageVersion Include="System.Text.RegularExpressions" Version="4.3.1" />
<PackageVersion Include="System.Threading.Tasks.Extensions" Version="4.6.0" />
<PackageVersion Include="System.Threading.Tasks.Extensions" Version="4.6.3" />
</ItemGroup>
</Project>
1 change: 0 additions & 1 deletion Documentation/GlobalTool.md
Original file line number Diff line number Diff line change
Expand Up @@ -275,5 +275,4 @@ Coverlet outputs specific exit codes to better support build automation systems
2 - Coverage percentage is below threshold.
3 - Test fails and also coverage percentage is below threshold.
101 - General exception occurred during coverlet process.
102 - Missing options or invalid arguments for coverlet process.
```
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"sdk": {
"version": "8.0.407"
"version": "8.0.409"
}
}
1 change: 0 additions & 1 deletion src/coverlet.collector/coverlet.collector.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
<Authors>tonerdo</Authors>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/coverlet-coverage/coverlet</PackageProjectUrl>
<PackageIconUrl>https://raw.githubusercontent.com/tonerdo/coverlet/master/_assets/coverlet-icon.svg?sanitize=true</PackageIconUrl>
<PackageIcon>coverlet-icon.png</PackageIcon>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
<Description>Coverlet is a cross platform code coverage library for .NET, with support for line, branch and method coverage.</Description>
Expand Down
5 changes: 0 additions & 5 deletions src/coverlet.console/ExitCodes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,5 @@ internal enum CommandExitCodes
/// Indicates exception occurred during Coverlet process.
/// </summary>
Exception = 101,

/// <summary>
/// Indicates missing options or empty arguments for Coverlet process.
/// </summary>
CommandParsingException = 102
}

29 changes: 15 additions & 14 deletions src/coverlet.console/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,17 @@ namespace Coverlet.Console
{
public static class Program
{
static int s_exitCode;
static int Main(string[] args)
{
var moduleOrAppDirectory = new Argument<string>("path", "Path to the test assembly or application directory.");
var target = new Option<string>(["--target", "-t"], "Path to the test runner application.") { Arity = ArgumentArity.ZeroOrOne, IsRequired = true };
var targs = new Option<string>(["--targetargs", "-a"], "Arguments to be passed to the test runner.") { Arity = ArgumentArity.ZeroOrOne };
var output = new Option<string>(["--output", "-o"], "Output of the generated coverage report") { Arity = ArgumentArity.ZeroOrOne };
var verbosity = new Option<LogLevel>(["--verbosity", "-v"], () => LogLevel.Normal, "Sets the verbosity level of the command. Allowed values are quiet, minimal, normal, detailed.") { Arity = ArgumentArity.ZeroOrOne };
var formats = new Option<string[]>(["--format", "-f"], () => ["json"], "Format of the generated coverage report.") { Arity = ArgumentArity.ZeroOrMore, AllowMultipleArgumentsPerToken = true };
var formats = new Option<string[]>(aliases: ["--format", "-f"], getDefaultValue: () => ["json"], description: "Format of the generated coverage report.") { Arity = ArgumentArity.ZeroOrMore, AllowMultipleArgumentsPerToken = true }.FromAmong("json", "lcov", "opencover", "cobertura", "teamcity");
var threshold = new Option<string>("--threshold", "Exits with error if the coverage % is below value.") { Arity = ArgumentArity.ZeroOrOne };
Option<List<string>> thresholdTypes = new Option<List<string>>("--threshold-type", () => new List<string>(new string[] { "line", "branch", "method" }), "Coverage type to apply the threshold to.").FromAmong("line", "branch", "method");
Option<List<string>> thresholdTypes = new Option<List<string>>("--threshold-type", () => ["line", "branch", "method"], "Coverage type to apply the threshold to.").FromAmong("line", "branch", "method");
var thresholdStat = new Option<ThresholdStatistic>("--threshold-stat", () => ThresholdStatistic.Minimum, "Coverage statistic used to enforce the threshold value.") { Arity = ArgumentArity.ZeroOrOne };
var excludeFilters = new Option<string[]>("--exclude", "Filter expressions to exclude specific modules and types.") { Arity = ArgumentArity.ZeroOrMore, AllowMultipleArgumentsPerToken = true };
var includeFilters = new Option<string[]>("--include", "Filter expressions to include only specific modules and types.") { Arity = ArgumentArity.ZeroOrMore, AllowMultipleArgumentsPerToken = true };
Expand All @@ -47,7 +48,7 @@ static int Main(string[] args)
var mergeWith = new Option<string>("--merge-with", "Path to existing coverage result to merge.") { Arity = ArgumentArity.ZeroOrOne };
var useSourceLink = new Option<bool>("--use-source-link", "Specifies whether to use SourceLink URIs in place of file system paths.") { Arity = ArgumentArity.Zero };
var doesNotReturnAttributes = new Option<string[]>("--does-not-return-attribute", "Attributes that mark methods that do not return") { Arity = ArgumentArity.ZeroOrMore, AllowMultipleArgumentsPerToken = true };
var excludeAssembliesWithoutSources = new Option<string>("--exclude-assemblies-without-sources", "Specifies behavior of heuristic to ignore assemblies with missing source documents.") { Arity = ArgumentArity.ZeroOrOne };
Option<string> excludeAssembliesWithoutSources = new Option<string>("--exclude-assemblies-without-sources", () => "MissingAll", "Specifies behavior of heuristic to ignore assemblies with missing source documents.").FromAmong("MissingAll", "MissingAny", "None");
var sourceMappingFile = new Option<string>("--source-mapping-file", "Specifies the path to a SourceRootsMappings file.") { Arity = ArgumentArity.ZeroOrOne };

RootCommand rootCommand = new()
Expand Down Expand Up @@ -175,7 +176,7 @@ string sourceMappingFile

// Adjust log level based on user input.
logger.Level = verbosity;
int exitCode = (int)CommandExitCodes.Success;
s_exitCode = (int)CommandExitCodes.Success;

try
{
Expand Down Expand Up @@ -357,44 +358,44 @@ string sourceMappingFile
logger.LogInformation(coverageTable.ToStringAlternative());
if (process.ExitCode > 0)
{
exitCode += (int)CommandExitCodes.TestFailed;
s_exitCode = (int)CommandExitCodes.TestFailed;
}

ThresholdTypeFlags thresholdTypeFlags = result.GetThresholdTypesBelowThreshold(thresholdTypeFlagValues, thresholdStat);
if (thresholdTypeFlags != ThresholdTypeFlags.None)
{
exitCode += (int)CommandExitCodes.CoverageBelowThreshold;
var exceptionMessageBuilder = new StringBuilder();
s_exitCode = (int)CommandExitCodes.CoverageBelowThreshold;
var errorMessageBuilder = new StringBuilder();
if ((thresholdTypeFlags & ThresholdTypeFlags.Line) != ThresholdTypeFlags.None)
{
exceptionMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} line coverage is below the specified {thresholdTypeFlagValues[ThresholdTypeFlags.Line]}");
errorMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} line coverage is below the specified {thresholdTypeFlagValues[ThresholdTypeFlags.Line]}");
}

if ((thresholdTypeFlags & ThresholdTypeFlags.Branch) != ThresholdTypeFlags.None)
{
exceptionMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} branch coverage is below the specified {thresholdTypeFlagValues[ThresholdTypeFlags.Branch]}");
errorMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} branch coverage is below the specified {thresholdTypeFlagValues[ThresholdTypeFlags.Branch]}");
}

if ((thresholdTypeFlags & ThresholdTypeFlags.Method) != ThresholdTypeFlags.None)
{
exceptionMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} method coverage is below the specified {thresholdTypeFlagValues[ThresholdTypeFlags.Method]}");
errorMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} method coverage is below the specified {thresholdTypeFlagValues[ThresholdTypeFlags.Method]}");
}
throw new InvalidOperationException(exceptionMessageBuilder.ToString());
logger.LogError(errorMessageBuilder.ToString());
}

return Task.FromResult(exitCode);
return Task.FromResult(s_exitCode);

}

catch (Win32Exception we) when (we.Source == "System.Diagnostics.Process")
{
logger.LogError($"Start process '{target}' failed with '{we.Message}'");
return Task.FromResult(exitCode > 0 ? exitCode : (int)CommandExitCodes.Exception);
return Task.FromResult(s_exitCode > 0 ? s_exitCode : (int)CommandExitCodes.Exception);
}
catch (Exception ex)
{
logger.LogError(ex.Message);
return Task.FromResult(exitCode > 0 ? exitCode : (int)CommandExitCodes.Exception);
return Task.FromResult(s_exitCode > 0 ? s_exitCode : (int)CommandExitCodes.Exception);
}

}
Expand Down
1 change: 0 additions & 1 deletion src/coverlet.console/coverlet.console.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
<PackageTags>coverage;testing;unit-test;lcov;opencover;quality</PackageTags>
<PackageReadmeFile>GlobalTool.md</PackageReadmeFile>
<PackageReleaseNotes>https://github.com/coverlet-coverage/coverlet/blob/master/Documentation/Changelog.md</PackageReleaseNotes>
<PackageIconUrl>https://raw.githubusercontent.com/tonerdo/coverlet/master/_assets/coverlet-icon.svg?sanitize=true</PackageIconUrl>
<PackageIcon>coverlet-icon.png</PackageIcon>
<PackageProjectUrl>https://github.com/coverlet-coverage/coverlet</PackageProjectUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
Expand Down
1 change: 0 additions & 1 deletion src/coverlet.msbuild.tasks/coverlet.msbuild.tasks.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
<Authors>tonerdo</Authors>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/coverlet-coverage/coverlet</PackageProjectUrl>
<PackageIconUrl>https://raw.githubusercontent.com/tonerdo/coverlet/master/_assets/coverlet-icon.svg?sanitize=true</PackageIconUrl>
<PackageIcon>coverlet-icon.png</PackageIcon>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
<DevelopmentDependency>true</DevelopmentDependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.6.0" />
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.6.3" />
</ItemGroup>

</Project>
23 changes: 17 additions & 6 deletions test/coverlet.integration.template/DeepThought.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
namespace Coverlet.Integration.Template
namespace Coverlet.Integration.Template
{
public class DeepThought
public class DeepThought
{
public int AnswerToTheUltimateQuestionOfLifeTheUniverseAndEverything()
{
public int AnswerToTheUltimateQuestionOfLifeTheUniverseAndEverything()
{
return 42;
}
return 42;
}

// This method is not covered by any test
// It is here to demonstrate how Coverlet will report on untested code
// required for Coverlet.Integration.Tests.DotnetGlobalTools.StandAloneThreshold
// required for Coverlet.Integration.Tests.DotnetGlobalTools.DotnetToolThreshold
public void TheUntestedMethod()
{
#pragma warning disable CS0219 // Variable is assigned but its value is never used
string s = "this will never be covered by any test";
#pragma warning restore CS0219 // Variable is assigned but its value is never used
}
}
}
Loading