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
Target framework sets #1668
Target framework sets #1668
Conversation
2a704a3
to
fe3fcb0
Compare
fe3fcb0
to
4b0048a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm having some difficulties with this. In particular, the netcore3.0 set doesn't work for me (I'm still on a preview at work, though). First, I hacked the build program to make it easier for me to work with:
diff --git a/tools/FakeItEasy.Build/Program.cs b/tools/FakeItEasy.Build/Program.cs
index dd9e571..b43bb81 100644
--- a/tools/FakeItEasy.Build/Program.cs
+++ b/tools/FakeItEasy.Build/Program.cs
@@ -56,11 +56,20 @@ namespace FakeItEasy.Build
public static void Main(string[] args)
{
+ var targetFrameworkSet = "full";
+ foreach (var arg in args)
+ {
+ if (arg.StartsWith("TargetFrameworkSet="))
+ {
+ targetFrameworkSet = arg.Split('=')[1];
+ }
+ }
+
Target("default", DependsOn("unit", "integ", "spec", "approve", "pack"));
Target(
"build",
- () => Run("dotnet", "build FakeItEasy.sln -c Release /maxcpucount /nr:false /verbosity:minimal /nologo /bl:artifacts/logs/build.binlog"));
+ () => Run("dotnet", $"build FakeItEasy.sln -c Release /maxcpucount /nr:false /verbosity:minimal /nologo /bl:artifacts/logs/build.binlog /p:TargetFrameworkSet={targetFrameworkSet}"));
foreach (var testSuite in TestSuites)
{
@@ -68,14 +77,14 @@ namespace FakeItEasy.Build
testSuite.Key,
DependsOn("build"),
forEach: testSuite.Value,
- action: testDirectory => Run("dotnet", "test --configuration Release --no-build -- RunConfiguration.NoAutoReporters=true", testDirectory));
+ action: testDirectory => Run("dotnet", $"test --configuration Release --no-build /p:TargetFrameworkSet={targetFrameworkSet} -- RunConfiguration.NoAutoReporters=true", testDirectory));
}
Target(
"pack",
DependsOn("build", "pdbgit"),
forEach: ProjectsToPack,
- action: project => Run("dotnet", $"pack {project.Path} --configuration Release --no-build --output {Path.GetFullPath("artifacts/output")}"));
+ action: project => Run("dotnet", $"pack {project.Path} --configuration Release --no-build --output {Path.GetFullPath("artifacts/output")} /p:TargetFrameworkSet={targetFrameworkSet}"));
Target(
"pdbgit",
@@ -83,7 +92,7 @@ namespace FakeItEasy.Build
forEach: Pdbs.Where(pdb => File.Exists(pdb.Path)),
action: pdb => Run(ToolPaths.PdbGit, $"-u https://github.com/FakeItEasy/FakeItEasy -s {pdb.Path}"));
- RunTargetsAndExit(args, messageOnly: ex => ex is NonZeroExitCodeException);
+ RunTargetsAndExit(args.Where(arg => !arg.Contains('=')), messageOnly: ex => ex is NonZeroExitCodeException);
}
private class Pdb
Then I ran .\build.cmd TargetFrameworkSet=netcore3.0
and got:
D:\Sandbox\FakeItEasy\tests\FakeItEasy.Tests.TestHelpers\FakeItEasy.Tests.TestHelpers.csproj :
error NU1201: Project FakeItEasy is not compatible with netstandard2.0 (.NETStandard,Version=v2.0).
Project FakeItEasy supports: netstandard2.1 (.NETStandard,Version=v2.1)
[D:\Sandbox\FakeItEasy\FakeItEasy.sln]
Probably because we didn't build FIE 2.0 in this run.
Indeed, changing TestHelpersTargetFrameworks
to netstandard2.1 for this TargetFrameworkSet resolved the problem…
Or maybe I'm doing things wrong, since the "full" build works fine.
</PropertyGroup> | ||
|
||
<PropertyGroup Condition="'$(TargetFramework)' == 'netstandard1.6'"> | ||
<DefineConstants>$(DefineConstants);FEATURE_NETCORE_REFLECTION;USE_RUNTIMELOADER;FEATURE_EXCEPTION_DISPATCH_INFO;FEATURE_ARRAY_EMPTY;FEATURE_PARAMETERINFO_CUSTOMATTRIBUTES_PROPERTY</DefineConstants> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am surprised some of these constants (e.g. FEATURE_ARRAY_EMPTY
) don't need to be set for netstandard2.0. Or at least can't be set…
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh. I must have copied this from FakeItEasy.csproj... We don't use FEATURE_ARRAY_EMPTY
in the tests anyway. I'll fix this and leave only the necessary ones.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we both forgot about this comment as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops! Sorry
@@ -17,7 +17,10 @@ public static class ObjectAssertionsExtensions | |||
/// <param name="assertion">A FluentAssertions assertion that has been initiated on a subject.</param> | |||
public static void BeAFake(this ReferenceTypeAssertions<object, ObjectAssertions> assertion) | |||
{ | |||
Guard.AgainstNull(assertion, nameof(assertion)); | |||
if (assertion == null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rather than make FakeItEasy's internals visible to this project, I assume?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. At this point. If you prefer, I can add a InternalsVisibleTo
attribute to FIE
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't mind either way. What you have is fine. Thanks for asking.
Directory.Build.props
Outdated
|
||
<!-- .NET Framework only --> | ||
<PropertyGroup Condition=" '$(TargetFrameworkSet)' == 'netfx' "> | ||
<FakeItEasyTargetFrameworks>net45</FakeItEasyTargetFrameworks> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and net40 as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the goal was to make the build faster, I thought it would make sense to include as few TFMs as possible. Is there a scenario where we would want to build all netfx targets, and nothing else?
But the target sets I defined here are mostly examples anyway. The idea is that we can add new ones as needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah. I was taking "netcoreall" for comparison, without paying attention to the "all" on the end of that.
I don't mind excluding net40 from the set, but maybe in this case, rename to net45, since we're closer to a "netcore2.1" situation than a "netcoreall" situation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. I don't think a netfxall
is very useful. I intended netcoreall
to be the default for non-Windows build (could be set automatically based on the OS)
Directory.Build.props
Outdated
<ApprovalTestsTargetFrameworks>net461</ApprovalTestsTargetFrameworks> | ||
</PropertyGroup> | ||
|
||
<!-- .NET Core 3 / .NET Standard 2.0 --> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.NET Standard 2.1?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes! Forgot to update after I rebased
Directory.Build.props
Outdated
<IntegrationTestsTargetFrameworks>netcoreapp3.0</IntegrationTestsTargetFrameworks> | ||
<UnitTestsTargetFrameworks>netcoreapp3.0</UnitTestsTargetFrameworks> | ||
<AnalyzerTestsTargetFrameworks>netcoreapp3.0</AnalyzerTestsTargetFrameworks> | ||
<TestHelpersTargetFrameworks>netstandard2.0</TestHelpersTargetFrameworks> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about this. See my summary.
Oops. Seems broken for me too. Must have broke when I rebased. I'll look into it. |
In general, what do you think about this approach? <Import Project="$(MSBuildThisFileDirectory)/FakeItEasy.user.props" Condition="Exists('$(MSBuildThisFileDirectory)/FakeItEasy.user.props')" /> This way, there would be no need to temporarily edit Directory.Build.props |
4b0048a
to
d7cc4bd
Compare
As a possible improvement, I could move the "target framework set definitions" to separate files, which we import based on the value of
This would be mostly to make the Directory.Build.props file look cleaner Also, I'm not sure about the name of the concept. "Target framework set" is what I came up with, but let me know if you have a better idea. "Build profile", maybe? |
I think the approach is good. I'm not sure I'll use the feature that often, but who knows? I use I liked adding a parameter to the build script as well. The problem is that it's not discoverable as is, and as you and M. Ralph noted, adding parameters that aren't handled by Bullseye can be problematic. I toyed with the idea of adding targets to set the targetframeworkset (e.g.
Yes, please. Better than temporarily editing anything. Until we edit that file and forget to unedit! 😆
I'm ambivalent. Cleaner main file, but more files to look at. Do whichever you think is best.
I found "target framework set" to be comprehensible, so I was content. But since you put "build profile" in front of my face, I find I like it more… |
I think I would. In fact, I think I will almost always set the target framework set to
Look here for a workaround. Not ideal, but it gets the job done.
It's a good option too. But I think I like something like
Will do 👍
I'll try it and we'll see how it goes.
Build profile it is, then! |
I pushed new commits for the changes we discussed, let me know what you think. |
(I didn't implement the changes in the build script yet) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good, @thomaslevesque. One minor comment, which I don't care that much if you change anything for. I'm content for you to add docs and squash!
profiles/netcoreall.props
Outdated
<PropertyGroup> | ||
<FakeItEasyTargetFrameworks>netstandard1.6;netstandard2.0;netstandard2.1</FakeItEasyTargetFrameworks> | ||
<ValueTaskExtensionsTargetFrameworks>netstandard1.6;netstandard2.0;netstandard2.1</ValueTaskExtensionsTargetFrameworks> | ||
<ExampleTargetFrameworks>netcoreapp2.1</ExampleTargetFrameworks> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I expected 2.1 and 3.0.
If the thinking was that they're just examples, so we probably don't need to build both, maybe default to the newer framework? I can live with it as is, though.
(Actually, this brings up a similar question for the full profile, and which frameworks we should target for the examples and the approval tests - if we're just going to target one in each build profile, should it be the latest/most portable? Or maybe it's all fine.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the thinking was that they're just examples, so we probably don't need to build both
Yes, that's what I had in mind
maybe default to the newer framework?
👍
(Actually, this brings up a similar question for the full profile, and which frameworks we should target for the examples and the approval tests - if we're just going to target one in each build profile, should it be the latest/most portable? Or maybe it's all fine.)
The latest for each profile is a good choice, I think.
f2aa766
to
9bafe0c
Compare
I changed the TFM for the example projects, squashed fixup commits, and updated the docs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, @thomaslevesque. One question and one minor grammatical nit.
Otherwise, great. I enjoyed the docs. Very explainy!
<IntegrationTestsTargetFrameworks>netcoreapp1.0;netcoreapp2.1;netcoreapp3.0</IntegrationTestsTargetFrameworks> | ||
<UnitTestsTargetFrameworks>netcoreapp1.0;netcoreapp2.1;netcoreapp3.0</UnitTestsTargetFrameworks> | ||
<AnalyzerTestsTargetFrameworks>netcoreapp2.1;netcoreapp3.0</AnalyzerTestsTargetFrameworks> | ||
<TestHelpersTargetFrameworks>netstandard1.6;netstandard2.0;netstandard2.1</TestHelpersTargetFrameworks> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why a netstandard2.1 here but not in full?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A mistake. TestHelpers doesn't need a netstandard2.1 target
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And it also shouldn't be netstandard2.1 for the netcore3.0 profile
how_to_build.md
Outdated
FakeItEasy targets multiple versions of .NET (.NET Framework 4.0 and 4.5, .NET | ||
Standard 1.6, 2.0 and 2.1), and the tests also run on multiple frameworks (.NET | ||
Framework 4.6.1 and several versions of .NET Core). A consequence is that a full | ||
build can take a significant time. When working on the code, you might want a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"take a significant time" hits my ear funny. I'd've written "take a significant amount of time". Or perhaps "take significant time".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, thanks. Not being an native English speaker, it can sometimes be hard to tell what will sound funny to a native speaker...
9bafe0c
to
30a4801
Compare
Fixed and squashed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's the review that never ends. Sorry.
profiles/netcore3.0.props
Outdated
<IntegrationTestsTargetFrameworks>netcoreapp3.0</IntegrationTestsTargetFrameworks> | ||
<UnitTestsTargetFrameworks>netcoreapp3.0</UnitTestsTargetFrameworks> | ||
<AnalyzerTestsTargetFrameworks>netcoreapp3.0</AnalyzerTestsTargetFrameworks> | ||
<TestHelpersTargetFrameworks>netstandard2.0</TestHelpersTargetFrameworks> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I use the FakeItEasy.user.props
file to set the build profile to netcore3.0 (which was fun), and run build integ
, I again get
D:\Sandbox\FakeItEasy\tests\FakeItEasy.Tests.TestHelpers\FakeItEasy.Tests.TestHelpers.csproj :
error NU1201: Project FakeItEasy is not compatible with netstandard2.0 (.NETStandard,Version=v2.0).
Project FakeItEasy supports: netstandard2.1 (.NETStandard,Version=v2.1) [D:\Sandbox\FakeItEasy\FakeItEasy.sln]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Argh... OK, I'll really review and test those TFMs before I push a new fix.
</PropertyGroup> | ||
|
||
<PropertyGroup Condition="'$(TargetFramework)' == 'netstandard1.6'"> | ||
<DefineConstants>$(DefineConstants);FEATURE_NETCORE_REFLECTION;USE_RUNTIMELOADER;FEATURE_EXCEPTION_DISPATCH_INFO;FEATURE_ARRAY_EMPTY;FEATURE_PARAMETERINFO_CUSTOMATTRIBUTES_PROPERTY</DefineConstants> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we both forgot about this comment as well.
And upgrade ApprovalTests
30a4801
to
76c1139
Compare
My fault... It should be fixed now |
Hey. Packing fails in a clean sandbox with a non-full build. e.g. when I build netcore3.0. Perhaps we should take a page out of the main package's book and use something like
in FakeItEasy.Extensions.ValueTask.csproj |
Oh :(
Yes, I think I'll do that. Although I intended to drop that at some point and use |
In fact, it doesn't work, because it also takes netstandard2.1, which should be excluded... |
<None Include="$(OutputPath)/net45/$(AssemblyName).pdb" Pack="true" PackagePath="lib/net45" Visible="false" Condition="Exists('$(OutputPath)/net45/$(AssemblyName).pdb')" />
<None Include="$(OutputPath)/netstandard1.6/$(AssemblyName).pdb" Pack="true" PackagePath="lib/netstandard1.6" Visible="false" Condition="Exists('$(OutputPath)/netstandard1.6/$(AssemblyName).pdb')" />
<None Include="$(OutputPath)/netstandard2.0/$(AssemblyName).pdb" Pack="true" PackagePath="lib/netstandard2.0" Visible="false" Condition="Exists('$(OutputPath)/netstandard2.0/$(AssemblyName).pdb')" /> ? |
It's an option. But if the PDBs are there from a previous build, it would include them even when they're not in the selected TFMs. I have another option in mind, let me try... |
76c1139
to
2d1efaf
Compare
Well, my thing didn't work. I found another way, which isn't great, but the end result is slightly cleaner than before
Actually, it doesn't really matter, because we will only ever publish packages produced by the full build anyway. |
<SignAssembly>true</SignAssembly> | ||
<IncludeBuildOutput>false</IncludeBuildOutput> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This causes the Pack
target to not include .dll and .xml files from the build output. I include them manually, which gives me control over what goes into the package.
<SignAssembly>true</SignAssembly> | ||
<IncludeBuildOutput>false</IncludeBuildOutput> | ||
<BeforePack>AddNetStd21Placeholder;$(BeforePackOn)</BeforePack> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cleaner than depending on _WalkEachTargetPerFramework
, which is a private target
<None Include="$(OutputPath)/**/$(AssemblyName).dll" Pack="true" PackagePath="lib" Visible="false" /> | ||
<None Include="$(OutputPath)/**/$(AssemblyName).pdb" Pack="true" PackagePath="lib" Visible="false" /> | ||
<None Include="$(OutputPath)/**/$(AssemblyName).xml" Pack="true" PackagePath="lib" Visible="false" /> | ||
<None Remove="$(OutputPath)/netstandard2.1/*" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I include everything, then exclude what I don't want
Nice job, @thomaslevesque! Thanks for your work. |
Thanks for the careful review! |
Fixes #1662
To be merged after #1667