Skip to content

Commit 0dce893

Browse files
author
eddie.stanley
committed
[andrewabestGH-87] Added new convention to enforce that a given project doesn't include project references to (any) other projects
1 parent 5a2ff26 commit 0dce893

File tree

3 files changed

+64
-0
lines changed

3 files changed

+64
-0
lines changed

src/Core/Conventional.Tests/Conventional/Conventions/Assemblies/AssemblyConventionSpecificationTests.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,5 +219,27 @@ public void MustBeIncludedInSetOfAssemblies_Failure()
219219
// TODO: Use result.Should().AllSatisfy() once we've updated to fluentassertions 6.5.0+
220220
result.Select(x => x.IsSatisfied).Distinct().Single().Should().BeFalse();
221221
}
222+
223+
[Test]
224+
public void MustNotIncludeProjectReferences_Success()
225+
{
226+
var result = TheAssembly
227+
.WithNameMatching("TestProjectTwo")
228+
.MustConformTo(Convention.MustNotIncludeProjectReferences);
229+
230+
// TestProjectTwo doesn't import any other projects (at time of writing)
231+
result.IsSatisfied.Should().BeTrue();
232+
}
233+
234+
[Test]
235+
public void MustNotIncludeProjectReferences_Failure()
236+
{
237+
var result = TheAssembly
238+
.WithNameMatching("Conventional.Tests")
239+
.MustConformTo(Convention.MustNotIncludeProjectReferences); // It of course includes a reference to Conventional
240+
241+
result.IsSatisfied.Should().BeFalse();
242+
result.Failures.Single().Should().StartWith("Conventional.Tests includes reference to project");
243+
}
222244
}
223245
}

src/Core/Conventional/Convention.Assembly.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,5 +81,8 @@ public static MustBeIncludedInSetOfAssembliesConventionSpecification MustBeInclu
8181
{
8282
return new MustBeIncludedInSetOfAssembliesConventionSpecification(assemblies, setName);
8383
}
84+
85+
public static MustNotIncludeProjectReferencesConventionSpecification MustNotIncludeProjectReferences =>
86+
new MustNotIncludeProjectReferencesConventionSpecification();
8487
}
8588
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using System.Xml.Linq;
4+
using System.Xml.XPath;
5+
6+
namespace Conventional.Conventions.Assemblies
7+
{
8+
public class MustNotIncludeProjectReferencesConventionSpecification : AssemblyConventionSpecification
9+
{
10+
protected override ConventionResult IsSatisfiedBy(string assemblyName, XDocument projectDocument)
11+
{
12+
var projectReferences = GetProjectReferences(projectDocument).ToArray();
13+
14+
if (projectReferences.Any())
15+
{
16+
return ConventionResult.NotSatisfied(assemblyName, string.Format(FailureMessage, assemblyName, projectReferences.First()));
17+
}
18+
19+
return ConventionResult.Satisfied(assemblyName);
20+
}
21+
22+
protected override ConventionResult IsSatisfiedByLegacyCsprojFormat(string assemblyName, XDocument projectDocument)
23+
{
24+
return IsSatisfiedBy(assemblyName, projectDocument);
25+
}
26+
27+
private IEnumerable<string> GetProjectReferences(XDocument projectDocument)
28+
{
29+
// The Project element (and descendants) are namespaced in legacy csproj files, so our XPath ignores the
30+
// namespace by considering the local element name only. Once we no-longer need to support legacy csproj
31+
// files, the XPath can be simplified to /Project/ItemGroup/ProjectReference
32+
return projectDocument.XPathSelectElements("/*[local-name() = 'Project']/*[local-name() = 'ItemGroup']/*[local-name() = 'ProjectReference']")
33+
.Select(referenceElement => referenceElement.Attribute("Include")?.Value)
34+
.Where(value => value != null);
35+
}
36+
37+
protected override string FailureMessage => "{0} includes reference to project {1}";
38+
}
39+
}

0 commit comments

Comments
 (0)