Skip to content

Commit

Permalink
think maybe I'm happy now? (#1421)
Browse files Browse the repository at this point in the history
  • Loading branch information
david-driscoll authored Nov 19, 2024
1 parent c617a30 commit 1c82a0e
Show file tree
Hide file tree
Showing 5 changed files with 222 additions and 132 deletions.
66 changes: 40 additions & 26 deletions src/Nuke/IHaveCodeCoverage.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Xml.Linq;
using Nuke.Common.IO;

namespace Rocket.Surgery.Nuke;
Expand All @@ -11,20 +12,13 @@ namespace Rocket.Surgery.Nuke;
/// </remarks>
public interface IHaveCodeCoverage : IHaveArtifacts
{
/// <summary>
/// The directory where coverage artifacts are to be dropped
/// </summary>
[Parameter("The directory where coverage artifacts are to be dropped", Name = "Coverage")]
public AbsolutePath CoverageDirectory =>
EnvironmentInfo.GetVariable<AbsolutePath>("Coverage")
?? TryGetValue(() => CoverageDirectory)
?? NukeBuild.RootDirectory / "coverage";
public static IEnumerable<string> DefaultIncludeModulePaths => [];
public static IEnumerable<string> DefaultExcludeModulePaths => [];
public static IEnumerable<string> DefaultIncludeSources => [];
public static IEnumerable<string> DefaultExcludeSources => [];
public static IEnumerable<string> DefaultIncludeAttributes => [];

public IEnumerable<string> IncludeModulePaths => [];
public IEnumerable<string> ExcludeModulePaths => [];
public IEnumerable<string> IncludeAttributes => [];

public IEnumerable<string> ExcludeAttributes =>
public static IEnumerable<string> DefaultExcludeAttributes =>
[
"System.Diagnostics.DebuggerHiddenAttribute",
"System.Diagnostics.DebuggerNonUserCodeAttribute",
Expand All @@ -33,23 +27,43 @@ public interface IHaveCodeCoverage : IHaveArtifacts
"System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute",
];

public IEnumerable<string> IncludeNamespaces => [];
public static IEnumerable<string> DefaultIncludeNamespaces => [];

public IEnumerable<string> ExcludeNamespaces =>
public static IEnumerable<string> DefaultExcludeNamespaces =>
[
"Bogus.",
"FakeItEasy.",
"Moq.",
"NSubstitute.",
"Verify.",
"XUnit.",
"TUnit.",
"Bogus",
"FakeItEasy",
"Moq",
"NSubstitute",
"Verify",
"XUnit",
"TUnit",
"Microsoft.",
"System.",
"JetBrains.",
"DryIoc.",
"Nuke.",
"FluentAssertions.",
"Serilog.",
"DryIoc",
"Nuke",
"FluentAssertions",
"Serilog",
];

/// <summary>
/// The directory where coverage artifacts are to be dropped
/// </summary>
[Parameter("The directory where coverage artifacts are to be dropped", Name = "Coverage")]
public AbsolutePath CoverageDirectory =>
EnvironmentInfo.GetVariable<AbsolutePath>("Coverage")
?? TryGetValue(() => CoverageDirectory)
?? NukeBuild.RootDirectory / "coverage";

public IEnumerable<string> IncludeNamespaces => DefaultIncludeNamespaces;
public IEnumerable<string> ExcludeNamespaces => DefaultExcludeNamespaces;
public IEnumerable<string> IncludeAttributes => DefaultIncludeAttributes;
public IEnumerable<string> ExcludeAttributes => DefaultExcludeAttributes;
public IEnumerable<string> IncludeSources => DefaultIncludeSources;
public IEnumerable<string> ExcludeSources => DefaultExcludeSources;
public IEnumerable<string> IncludeModulePaths => DefaultIncludeModulePaths;
public IEnumerable<string> ExcludeModulePaths => DefaultExcludeModulePaths;

public XDocument CustomizeCoverageRunSettings(XDocument document) => document;
}
49 changes: 35 additions & 14 deletions src/Nuke/ITriggerCodeCoverageReports.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Nuke.Common.IO;
using Nuke.Common.Tooling;
using Nuke.Common.Tools.ReportGenerator;
using Rocket.Surgery.Nuke.ProjectModel;

// ReSharper disable SuspiciousTypeConversion.Global

Expand All @@ -13,7 +14,7 @@ namespace Rocket.Surgery.Nuke;
/// This causes code coverage to trigger
/// </remarks>
[PublicAPI]
public interface ITriggerCodeCoverageReports : IHaveCodeCoverage, IHaveTestTarget, IHaveTestArtifacts, ITrigger
public interface ITriggerCodeCoverageReports : IHaveCodeCoverage, IHaveTestTarget, IHaveTestArtifacts, ITrigger, IHaveSolution
{
/// <summary>
/// The input reports
Expand Down Expand Up @@ -89,17 +90,37 @@ public interface ITriggerCodeCoverageReports : IHaveCodeCoverage, IHaveTestTarge
/// </summary>
/// <param name="settings"></param>
/// <returns></returns>
protected ReportGeneratorSettings Defaults(ReportGeneratorSettings settings) => ( this switch
{
IHaveGitVersion gitVersion => settings.SetTag(
gitVersion.GitVersion.InformationalVersion
),
IHaveGitRepository { GitRepository: { } } gitRepository => settings
.SetTag(gitRepository.GitRepository.Head),
_ => settings,
}
)
.SetReports(InputReports)
.SetSourceDirectories(NukeBuild.RootDirectory)
.SetFramework(Constants.ReportGeneratorFramework);
protected ReportGeneratorSettings Defaults(ReportGeneratorSettings settings)
=> ( this switch
{
IHaveGitVersion gitVersion => settings.SetTag(
gitVersion.GitVersion.InformationalVersion
),
IHaveGitRepository { GitRepository: { } } gitRepository => settings
.SetTag(gitRepository.GitRepository.Head),
_ => settings,
}
)
.SetReports(InputReports)
.SetSourceDirectories(NukeBuild.RootDirectory)
.SetFramework(Constants.ReportGeneratorFramework)
// this is more or less a hack / compromise because
// I was unable to coverage to exclude everything in a given assembly by default.
.AddAssemblyFilters(
Solution
.AnalyzeAllProjects()
.Select(z => z.GetProperty("AssemblyName") ?? "")
.Where(z => !string.IsNullOrWhiteSpace(z))
.Distinct()
.Select(z => "+" + z)
)
.AddAssemblyFilters(
Solution
.AnalyzeAllProjects()
.SelectMany(z => z.PackageReferences)
.Select(z => z.Name)
.Where(z => !string.IsNullOrWhiteSpace(z))
.Distinct()
.Select(z => "-" + z)
);
}
117 changes: 75 additions & 42 deletions src/Nuke/TestMethodExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System.Collections.Immutable;
using System.Xml.Linq;
using Nuke.Common.IO;
using Rocket.Surgery.Nuke.DotNetCore;
using Rocket.Surgery.Nuke.ProjectModel;

namespace Rocket.Surgery.Nuke;

Expand All @@ -19,7 +21,7 @@ public static class TestMethodExtensions
// ReSharper disable once IdentifierTypo
// ReSharper disable once StringLiteralTypo
public static ITargetDefinition EnsureRunSettingsExists<T>(this ITargetDefinition target, T build)
where T : IHaveCodeCoverage, IComprehendTests
where T : IHaveCodeCoverage, IComprehendTests, IHaveSolution
{
return target.Executes(
async () =>
Expand All @@ -38,28 +40,46 @@ await typeof(ICanTestWithDotNetCore)
.GetManifestResourceStream("Rocket.Surgery.Nuke.default.runsettings")!.CopyToAsync(tempFile);
}

var projects = build
.Solution.AnalyzeAllProjects()
.ToImmutableArray();
var includeNames = projects
.Select(z => z.GetProperty("AssemblyName") ?? "")
.Where(z => !string.IsNullOrWhiteSpace(z))
.Distinct()
.Select(z => ( z + ".dll" ).Replace(".", "\\."));
var excludePackages = projects
.SelectMany(z => z.PackageReferences)
.Select(z => z.Name)
.Where(z => !string.IsNullOrWhiteSpace(z))
.Distinct()
.Select(z => ( z + ".dll" ).Replace(".", "\\."));


ManageRunSettings(
build,
runsettings,
build.IncludeModulePaths,
build.ExcludeModulePaths,
build.IncludeAttributes,
build.ExcludeAttributes,
build.IncludeNamespaces,
build.ExcludeNamespaces
(
build.IncludeModulePaths.Union(includeNames),
build.ExcludeModulePaths.Union(excludePackages)
),
( build.IncludeAttributes, build.ExcludeAttributes ),
( build.IncludeNamespaces, build.ExcludeNamespaces ),
( build.IncludeSources, build.ExcludeSources )
);
}
);
}

private static void ManageRunSettings(
private static void ManageRunSettings<T>(
T build,
AbsolutePath runsettingsPath,
IEnumerable<string> includeModulePaths,
IEnumerable<string> excludeModulePaths,
IEnumerable<string> includeAttributes,
IEnumerable<string> excludeAttributes,
IEnumerable<string> includeNamespaces,
IEnumerable<string> excludeNamespaces
(IEnumerable<string> include, IEnumerable<string> exclude) modulePaths,
(IEnumerable<string> include, IEnumerable<string> exclude) attributes,
(IEnumerable<string> include, IEnumerable<string> exclude) namespaces,
(IEnumerable<string> include, IEnumerable<string> exclude) sources
)
where T : IHaveCodeCoverage, IComprehendTests
{
var doc = XDocument.Load(runsettingsPath);

Expand All @@ -81,27 +101,42 @@ IEnumerable<string> excludeNamespaces
dataCollector.Element("Configuration")?.Add(codeCoverage);
}

AddIncludeItems(codeCoverage, "ModulePaths", "ModulePath", includeModulePaths);
AddExcludeItems(codeCoverage, "ModulePaths", "ModulePath", excludeModulePaths);
AddIncludeItems(codeCoverage, "Attributes", "Attribute", includeAttributes.Select(TransformAttribute));
AddExcludeItems(codeCoverage, "Attributes", "Attribute", excludeAttributes.Select(TransformAttribute));
AddIncludeItems(codeCoverage, "Functions", "Function", includeNamespaces.Select(TransformNamespace));
AddExcludeItems(codeCoverage, "Functions", "Function", excludeNamespaces.Select(TransformNamespace));
AddItems(codeCoverage, "Attributes", "Attribute", transform(attributes, transformAttribute));
AddItems(codeCoverage, "Functions", "Function", transform(namespaces, transformNamespace));
AddItems(codeCoverage, "ModulePaths", "ModulePath", transform(modulePaths, transformModulePath));
AddItems(codeCoverage, "Sources", "Source", sources);

build.CustomizeCoverageRunSettings(doc);

DistinctAndOrganize(codeCoverage, "ModulePaths");
DistinctAndOrganize(codeCoverage, "Attributes");
DistinctAndOrganize(codeCoverage, "Functions");
DistinctAndOrganize(codeCoverage, "ModulePaths");
DistinctAndOrganize(codeCoverage, "Sources");

doc.Save(runsettingsPath);

static string TransformAttribute(string ns)
static (IEnumerable<string> include, IEnumerable<string> exclude) transform(
(IEnumerable<string> include, IEnumerable<string> exclude) attributes,
Func<string, IEnumerable<string>> transformer
)
{
return ( attributes.include.SelectMany(transformer), attributes.exclude.SelectMany(transformer) );
}


static IEnumerable<string> transformAttribute(string attr)
{
return $"^{ns.Replace(".", "\\.")}$";
return [$"^{attr.Replace(".", "\\.")}$"];
}

static string TransformNamespace(string ns)
static IEnumerable<string> transformModulePath(string ns)
{
return $"^{ns.Replace(".", "\\.")}.*";
return [$".*{ns}"];
}

static IEnumerable<string> transformNamespace(string ns)
{
return [$"^{ns.Replace(".", "\\.")}.*"];
}
}

Expand All @@ -117,47 +152,45 @@ private static XElement EnsureElement(XElement parent, string name)
return element;
}

private static void AddIncludeItems(XElement parent, string parentName, string childName, IEnumerable<string> values)
private static void AddItems(XElement parent, string parentName, string childName, (IEnumerable<string> include, IEnumerable<string> exclude) values)
{
var parentElement = EnsureElement(parent, parentName);
var element = EnsureElement(parentElement, "Include");
var include = EnsureElement(parentElement, "Include");
var exclude = EnsureElement(parentElement, "Exclude");

include.RemoveAll();
exclude.RemoveAll();

element.RemoveAll();
foreach (var value in values)
foreach (var value in values.include)
{
element.Add(new XElement(childName, value));
include.Add(new XElement(childName, value));
}
}

private static void AddExcludeItems(XElement parent, string parentName, string childName, IEnumerable<string> values)
{
var parentElement = EnsureElement(parent, parentName);
var element = EnsureElement(parentElement, "Exclude");

element.RemoveAll();
foreach (var value in values)
foreach (var value in values.exclude)
{
element.Add(new XElement(childName, value));
exclude.Add(new XElement(childName, value));
}
}

private static void DistinctAndOrganize(XElement parent, string parentName)
{
var element = EnsureElement(parent, parentName);
if (element.Element("Include") is { } include)
if (parent.Element(parentName) is not { } item) return;
if (item.Element("Include") is { } include)
{
var values = include.Elements().DistinctBy(z => z.Value).OrderBy(x => x.Value).ToArray();
include.RemoveAll();
include.Add([..values]);
if (!include.Elements().Any()) include.Remove();
}

if (element.Element("Exclude") is { } exclude)
if (item.Element("Exclude") is { } exclude)
{
var values = exclude.Elements().DistinctBy(z => z.Value).OrderBy(x => x.Value).ToArray();
exclude.RemoveAll();
exclude.Add([..values]);
if (!exclude.Elements().Any()) exclude.Remove();
}

if (!item.Elements().Any()) item.Remove();
}
}
Loading

0 comments on commit 1c82a0e

Please sign in to comment.