From e160a4c560abab329f8cce689afbb386c225f3f5 Mon Sep 17 00:00:00 2001 From: "eddie.stanley" Date: Fri, 5 Jan 2024 10:54:59 -0800 Subject: [PATCH] [GH-87] Added new convention to enforce that a given project doesn't include project references to (any) other projects --- .../AssemblyConventionSpecificationTests.cs | 22 ++++++++++++ src/Core/Conventional/Convention.Assembly.cs | 3 ++ ...rojectReferencesConventionSpecification.cs | 36 +++++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 src/Core/Conventional/Conventions/Assemblies/MustNotIncludeProjectReferencesConventionSpecification.cs diff --git a/src/Core/Conventional.Tests/Conventional/Conventions/Assemblies/AssemblyConventionSpecificationTests.cs b/src/Core/Conventional.Tests/Conventional/Conventions/Assemblies/AssemblyConventionSpecificationTests.cs index ccb5a9a..41d4232 100644 --- a/src/Core/Conventional.Tests/Conventional/Conventions/Assemblies/AssemblyConventionSpecificationTests.cs +++ b/src/Core/Conventional.Tests/Conventional/Conventions/Assemblies/AssemblyConventionSpecificationTests.cs @@ -219,5 +219,27 @@ public void MustBeIncludedInSetOfAssemblies_Failure() // TODO: Use result.Should().AllSatisfy() once we've updated to fluentassertions 6.5.0+ result.Select(x => x.IsSatisfied).Distinct().Single().Should().BeFalse(); } + + [Test] + public void MustNotIncludeProjectReferences_Success() + { + var result = TheAssembly + .WithNameMatching("TestProjectTwo") + .MustConformTo(Convention.MustNotIncludeProjectReferences); + + // TestProjectTwo doesn't import any other projects (at time of writing) + result.IsSatisfied.Should().BeTrue(); + } + + [Test] + public void MustNotIncludeProjectReferences_Failure() + { + var result = TheAssembly + .WithNameMatching("Conventional.Tests") + .MustConformTo(Convention.MustNotIncludeProjectReferences); // It of course includes a reference to Conventional + + result.IsSatisfied.Should().BeFalse(); + result.Failures.Single().Should().StartWith("Conventional.Tests includes reference to project"); + } } } \ No newline at end of file diff --git a/src/Core/Conventional/Convention.Assembly.cs b/src/Core/Conventional/Convention.Assembly.cs index 40c0a3e..0994ce7 100644 --- a/src/Core/Conventional/Convention.Assembly.cs +++ b/src/Core/Conventional/Convention.Assembly.cs @@ -81,5 +81,8 @@ public static MustBeIncludedInSetOfAssembliesConventionSpecification MustBeInclu { return new MustBeIncludedInSetOfAssembliesConventionSpecification(assemblies, setName); } + + public static MustNotIncludeProjectReferencesConventionSpecification MustNotIncludeProjectReferences => + new MustNotIncludeProjectReferencesConventionSpecification(); } } \ No newline at end of file diff --git a/src/Core/Conventional/Conventions/Assemblies/MustNotIncludeProjectReferencesConventionSpecification.cs b/src/Core/Conventional/Conventions/Assemblies/MustNotIncludeProjectReferencesConventionSpecification.cs new file mode 100644 index 0000000..c2cbea8 --- /dev/null +++ b/src/Core/Conventional/Conventions/Assemblies/MustNotIncludeProjectReferencesConventionSpecification.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; +using System.Xml.XPath; + +namespace Conventional.Conventions.Assemblies +{ + public class MustNotIncludeProjectReferencesConventionSpecification : AssemblyConventionSpecification + { + protected override ConventionResult IsSatisfiedBy(string assemblyName, XDocument projectDocument) + { + var projectReferences = GetProjectReferences(projectDocument).ToArray(); + + if (projectReferences.Any()) + { + return ConventionResult.NotSatisfied(assemblyName, string.Format(FailureMessage, assemblyName, projectReferences.First())); + } + + return ConventionResult.Satisfied(assemblyName); + } + + protected override ConventionResult IsSatisfiedByLegacyCsprojFormat(string assemblyName, XDocument projectDocument) + { + return IsSatisfiedBy(assemblyName, projectDocument); + } + + private IEnumerable GetProjectReferences(XDocument projectDocument) + { + return projectDocument.XPathSelectElements("/Project/ItemGroup/ProjectReference") + .Select(referenceElement => referenceElement.Attribute("Include")?.Value) + .Where(value => value != null); + } + + protected override string FailureMessage => "{0} includes reference to project {1}"; + } +} \ No newline at end of file