Skip to content
Merged
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: 8 additions & 2 deletions docs/input/guidelines/TargetFramework.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,24 @@ Title: Target Frameworks

## Goals

As .NET Framework < 4.7.2 has issues with running .NET Standard assemblies, and Cake itself can run on .NET Framework 4.6.1 it is suggested to multi-target addins to `netstandard2.0` and `net461` to have the maximum compatibility.
Each addin should have maximum compatibility when being used. Toward that end some Framework versions are required and some others are
suggested, depending on the Cake.Core version that is being referenced.

### Required / Suggested versions

Depending on the referenced `Cake.Core`-version different target versions are required and/or suggested.
Missing a required target version will raise [CCG0007](../rules/ccg0007) as an error
while missing a suggested target version will raise [CCG0007](../rules/ccg0007) as a warning.

* Cake.Core <= 0.33.0
* Cake.Core < 1.0.0
* Required: `netstandard2.0`
* Suggested: `net461`
* alternative: `net46`
* Cake.Core >= 1.0.0
* Required: `netstandard2.0`
* Suggested: `net461`
* alternative: `net46`
* Suggested: `net5.0`

## Related rules

Expand Down
6 changes: 3 additions & 3 deletions docs/input/rules/ccg0007.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ Also, This could be raised as an error, if a required target version is not set.

## Description

Addins should be multi-targeted to `netstandard2.0` and `net461` to have the maximum compatibility.
Addins should be multi-targeted to different framework versions to have the maximum compatibility.

## How to fix violations

Add the recommended target(s) to the project:
Add the recommended target(s) to the project (example for an addin referencing Cake.Core 1.0.0):

```xml
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net461</TargetFrameworks>
<TargetFrameworks>netstandard2.0;net461;net5.0</TargetFrameworks>
</PropertyGroup>
```

Expand Down
2 changes: 1 addition & 1 deletion src/Guidelines/build/TargetFrameworkVersions.targets
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<!-- All other rules have some "configuration" here, this rules required/suggested targets are hard-coded in the task. Sadly. -->

<TargetFrameworkVersions
References="@(Reference)"
References="@(PackageReference)"
TargetFramework="$(TargetFramework)"
TargetFrameworks="$(TargetFrameworks)"
Omitted="@(CakeContribGuidelinesOmitTargetFramework)"
Expand Down
41 changes: 33 additions & 8 deletions src/Tasks.IntegrationTests/E2eTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,7 @@ public void PackageIcon_Tag_with_modified_CakeContribGuidelinesIconDestinationLo
public void Referencing_Cake_Core_with_PrivateAssets_results_in_no_error()
{
// given
fixture.WithCustomContent($@"
<ItemGroup>
<PackageReference Include=""Cake.Core"" Version=""0.38.5"" PrivateAssets=""all"" />
</ItemGroup>");
fixture.WithPackageReference("Cake.Core", "0.38.5", "all");

// when
var result = fixture.Run();
Expand All @@ -120,10 +117,7 @@ public void Referencing_Cake_Core_with_PrivateAssets_results_in_no_error()
public void Referencing_Cake_Core_without_PrivateAssets_results_in_CCG0004_error()
{
// given
fixture.WithCustomContent($@"
<ItemGroup>
<PackageReference Include=""Cake.Core"" Version=""0.38.5"" />
</ItemGroup>");
fixture.WithPackageReference("Cake.Core", "0.38.5");

// when
var result = fixture.Run();
Expand Down Expand Up @@ -224,5 +218,36 @@ public void Missing_Suggested_Target_results_in_CCG0007_warning()
result.WarningLines.Should().Contain(l => l.IndexOf("CCG0007", StringComparison.Ordinal) > -1);
result.WarningLines.Should().Contain(l => l.IndexOf("net461", StringComparison.Ordinal) > -1);
}

[Fact]
public void Missing_Suggested_Target_net5_for_Cake_v100_results_in_CCG0007_warning()
{
// given
fixture.WithPackageReference("Cake.Core", "1.0.0", "all");
fixture.WithTargetFrameworks("netstandard2.0;net461");

// when
var result = fixture.Run();

// then
result.IsErrorExitCode.Should().BeFalse();
result.WarningLines.Should().Contain(l => l.IndexOf("CCG0007", StringComparison.Ordinal) > -1);
result.WarningLines.Should().Contain(l => l.IndexOf("net5.0", StringComparison.Ordinal) > -1);
}

[Fact]
public void Referencing_CakeCore_With_all_targets_raises_no_warning()
{
// given
fixture.WithPackageReference("Cake.Core", "1.0.0", "all");
fixture.WithTargetFrameworks("netstandard2.0;net461;net5.0");

// when
var result = fixture.Run();

// then
result.IsErrorExitCode.Should().BeFalse();
result.WarningLines.Should().BeEmpty();
}
}
}
25 changes: 25 additions & 0 deletions src/Tasks.IntegrationTests/Fixtures/E2eTestFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;

using Xunit.Abstractions;

Expand All @@ -20,6 +21,7 @@ public class E2eTestFixture : IDisposable
private bool hasEditorConfig = true;
private readonly List<string> customContent = new List<string>();
private string targetFrameworks = "netstandard2.0;net461";
private readonly List<string> references = new List<string>();

public E2eTestFixture(string tempFolder, ITestOutputHelper logger)
{
Expand Down Expand Up @@ -90,6 +92,7 @@ private string WriteProject()
<PrivateAssets>all</PrivateAssets>
</PackageReference>");
}
items.AddRange(references);

File.WriteAllText(csproj, string.Format(template,
targets.Item1,
Expand Down Expand Up @@ -122,6 +125,28 @@ internal void WithCustomContent(string content)
customContent.Add(content);
}

internal void WithPackageReference(
string packageName,
string version,
string privateAssets = null,
params Tuple<string, string>[] additionalAttributes)
{
var reference = new StringBuilder();
reference.Append($@"<PackageReference Include=""{packageName}"" Version=""{version}""");
if (privateAssets != null)
{
reference.Append($@" PrivateAssets=""{privateAssets}""");
}

foreach ((string key, string val) in additionalAttributes)
{
reference.Append($@" {key}=""{val}""");
}

reference.Append(" />");
references.Add(reference.ToString());
}

internal void WithoutStylecopReference()
{
hasStylecopReference = false;
Expand Down
71 changes: 37 additions & 34 deletions src/Tasks.Tests/Extensions/ExtensionTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;

using CakeContrib.Guidelines.Tasks.Extensions;

Expand All @@ -10,58 +11,60 @@ namespace CakeContrib.Guidelines.Tasks.Tests.Extensions
{
public class VersionExtensionTests
{
[Fact]
public void GreaterEqual_Is_True_For_Equal_Versions()
[Theory]
[MemberData(nameof(GetGreaterEqualData))]
public void GreaterEqualTheory(Version lhs, Version rhs, bool expected)
{
var a = new Version(1, 2, 3);
var b = new Version(a.Major, a.Minor, a.Build);

a.GreaterEqual(b).Should().BeTrue();
lhs.GreaterEqual(rhs).Should().Be(expected);
}

[Fact]
public void GreaterEqual_Is_True_For_Greater_Versions()
public static IEnumerable<object[]> GetGreaterEqualData()
{
var a = new Version(1, 2, 3);
var b = new Version(a.Major, a.Minor, a.Build - 1);

a.GreaterEqual(b).Should().BeTrue();
yield return new object[] { new Version(1, 2, 3), new Version(1, 2, 3), true };
yield return new object[] { new Version(1, 2, 3), new Version(1, 2, 2), true };
yield return new object[] { new Version(1, 2, 2), new Version(1, 2, 3), false };
}

[Fact]
public void GreaterEqual_Is_False_For_Lesser_Versions()
[Theory]
[MemberData(nameof(GetLessEqualData))]
public void LessEqualTheory(Version lhs, Version rhs, bool expected)
{
var a = new Version(1, 2, 3);
var b = new Version(a.Major, a.Minor, a.Build + 1);

a.GreaterEqual(b).Should().BeFalse();
lhs.LessEqual(rhs).Should().Be(expected);
}

[Fact]
public void LessEqual_Is_True_For_Equal_Versions()
public static IEnumerable<object[]> GetLessEqualData()
{
var a = new Version(1, 2, 3);
var b = new Version(a.Major, a.Minor, a.Build);

a.LessEqual(b).Should().BeTrue();
yield return new object[] { new Version(1, 2, 3), new Version(1, 2, 3), true };
yield return new object[] { new Version(1, 2, 3), new Version(1, 2, 2), false };
yield return new object[] { new Version(1, 2, 2), new Version(1, 2, 3), true };
}

[Fact]
public void LessEqual_Is_True_For_Lesser_Versions()
[Theory]
[MemberData(nameof(GetGreaterThanData))]
public void GreaterThanTheory(Version lhs, Version rhs, bool expected)
{
var a = new Version(1, 2, 3);
var b = new Version(a.Major, a.Minor, a.Build + 1);
lhs.GreaterThan(rhs).Should().Be(expected);
}

a.LessEqual(b).Should().BeTrue();
public static IEnumerable<object[]> GetGreaterThanData()
{
yield return new object[] { new Version(1, 2, 3), new Version(1, 2, 3), false };
yield return new object[] { new Version(1, 2, 3), new Version(1, 2, 2), true };
yield return new object[] { new Version(1, 2, 2), new Version(1, 2, 3), false };
}

[Fact]
public void LessEqual_Is_False_For_Greater_Versions()
[Theory]
[MemberData(nameof(GetLessThanData))]
public void LessThanTheory(Version lhs, Version rhs, bool expected)
{
var a = new Version(1, 2, 3);
var b = new Version(a.Major, a.Minor, a.Build - 1);
lhs.LessThan(rhs).Should().Be(expected);
}

a.LessEqual(b).Should().BeFalse();
public static IEnumerable<object[]> GetLessThanData()
{
yield return new object[] { new Version(1, 2, 3), new Version(1, 2, 3), false };
yield return new object[] { new Version(1, 2, 3), new Version(1, 2, 2), false };
yield return new object[] { new Version(1, 2, 2), new Version(1, 2, 3), true };
}
}
}
5 changes: 4 additions & 1 deletion src/Tasks.Tests/Fixtures/RequiredReferencesFixture.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;

using Microsoft.Build.Framework;
Expand Down Expand Up @@ -50,7 +51,9 @@ public void WithReferencedPackage(string packageName, string privateAssets = "")
{
var referencedPackage = new Mock<ITaskItem>();
referencedPackage.Setup(x => x.ToString()).Returns(packageName);
referencedPackage.Setup(x => x.GetMetadata("PrivateAssets")).Returns(privateAssets);
referencedPackage.Setup(x => x.GetMetadata(
It.Is<string>(y => "PrivateAssets".Equals(y, StringComparison.OrdinalIgnoreCase))))
.Returns(privateAssets);
references.Add(referencedPackage.Object);
}
}
Expand Down
13 changes: 8 additions & 5 deletions src/Tasks.Tests/Fixtures/TargetFrameworkVersionsFixture.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;

Expand Down Expand Up @@ -31,25 +32,27 @@ public override bool Execute()
return base.Execute();
}

public void WithTargetFramwork(string packageName)
public void WithTargetFramework(string packageName)
{
targetFramework = GetMockTaskItem(packageName).Object;
}

public void WithTargetFramworks(params string[] packageNames)
public void WithTargetFrameworks(params string[] packageNames)
{
targetFrameworks.AddRange(packageNames.Select(n => GetMockTaskItem(n).Object));
}

public void WithOmittedTargetFramework(string targetFramework)
public void WithOmittedTargetFramework(string targetFrameworkToOmit)
{
omittedTargets.Add(GetMockTaskItem(targetFramework).Object);
omittedTargets.Add(GetMockTaskItem(targetFrameworkToOmit).Object);
}

public void WithCakeCoreReference(int major = 0, int minor = 0, int patch = 0)
{
var cakeRef = GetMockTaskItem("Cake.Core");
cakeRef.Setup(x => x.GetMetadata("Version")).Returns($"{major}.{minor}.{patch}");
cakeRef.Setup(x => x.GetMetadata(
It.Is<string>(y => "version".Equals(y, StringComparison.OrdinalIgnoreCase))))
.Returns($"{major}.{minor}.{patch}");
references.Add(cakeRef.Object);
}

Expand Down
Loading