From e9430c0d76ce1d7c413df71e08592cc92eb2be39 Mon Sep 17 00:00:00 2001 From: Daniel Cazzulino Date: Wed, 21 Oct 2020 16:40:15 -0300 Subject: [PATCH 1/2] By default, packing Compile should not include generated files Like the target framework attribute and assembly info. Additional exclusions should be configurable as needed, so we moved the item to a .props file so the project can update/remove as needed. This adds another customization point too, allowing to tweak the exclusions for any PackInference (i.e. for Content, EmbeddedResource, None and so on). --- README.md | 26 +++++++++ src/NuGetizer.Tasks/NuGetizer.Inference.props | 21 +++++++ .../NuGetizer.Inference.targets | 13 ++--- src/NuGetizer.Tasks/NuGetizer.props | 1 + src/NuGetizer.Tests/Builder.NuGetizer.cs | 13 ++--- src/NuGetizer.Tests/Scenarios/Scenario.props | 4 ++ .../Scenarios/Scenario.targets | 4 -- .../Scenarios/given_a_library/Api/Api.cs | 0 .../Scenarios/given_a_library/Class1.cs | 0 .../Scenarios/given_a_library/library.csproj | 18 ++++++ src/NuGetizer.Tests/given_a_library.cs | 58 +++++++++++++++++++ 11 files changed, 139 insertions(+), 19 deletions(-) create mode 100644 src/NuGetizer.Tasks/NuGetizer.Inference.props create mode 100644 src/NuGetizer.Tests/Scenarios/given_a_library/Api/Api.cs create mode 100644 src/NuGetizer.Tests/Scenarios/given_a_library/Class1.cs create mode 100644 src/NuGetizer.Tests/Scenarios/given_a_library/library.csproj create mode 100644 src/NuGetizer.Tests/given_a_library.cs diff --git a/README.md b/README.md index 6545b7db..e54bbb7b 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,32 @@ Whether items are packed by default or not is controlled by properties named aft \* Back in the day, PDBs were Windows-only and fat files. Nowadays, portable PDBs (the new default) are lightweight and can even be embedded. Combined with [SourceLink](https://github.com/dotnet/sourcelink), including them in the package (either standalone or embeded) provides the best experience for your users, so it's the default. +The various supported item inference are surfaced as `` items, which are ultimately evaluated together with the metadata for the individual items. These make the package inference candidates. You can also provide an exclude expression for that evaluation so that certain items are excluded by default, even if every other item of the same type is included. For example, to pack all `Content` items, except those in the `docs` folder, you can simply update the inference item like so: + +```xml + + + +``` + +Of course you could have achieved a similar effect by updating the Content items themselves too instead: + +```xml + + + +``` + +By default (see [NuGetizer.Inference.props](src/NuGetizer.Tasks/NuGetizer.Inference.props)), `Compile` has the following exclude expression, so generated intermediate compile files aren't packed: + +```xml + + + +``` + + ### CopyToOutputDirectory There is a common metadata item that's used quite frequently: *CopyToOutputDirectory*, which is typically set to *PreserveNewest* to change it from its default behavior (when empty or set to *Never*). diff --git a/src/NuGetizer.Tasks/NuGetizer.Inference.props b/src/NuGetizer.Tasks/NuGetizer.Inference.props new file mode 100644 index 00000000..04acd0f0 --- /dev/null +++ b/src/NuGetizer.Tasks/NuGetizer.Inference.props @@ -0,0 +1,21 @@ + + + + + + + + + diff --git a/src/NuGetizer.Tasks/NuGetizer.Inference.targets b/src/NuGetizer.Tasks/NuGetizer.Inference.targets index e8c804eb..55a7937d 100644 --- a/src/NuGetizer.Tasks/NuGetizer.Inference.targets +++ b/src/NuGetizer.Tasks/NuGetizer.Inference.targets @@ -104,7 +104,10 @@ Copyright (c) .NET Foundation. All rights reserved. true BundleResource - + + + + @@ -163,16 +166,10 @@ Copyright (c) .NET Foundation. All rights reserved. Pack="false" /> - - - - - + true diff --git a/src/NuGetizer.Tasks/NuGetizer.props b/src/NuGetizer.Tasks/NuGetizer.props index ed43497f..8b77441e 100644 --- a/src/NuGetizer.Tasks/NuGetizer.props +++ b/src/NuGetizer.Tasks/NuGetizer.props @@ -146,6 +146,7 @@ Copyright (c) .NET Foundation. All rights reserved. + diff --git a/src/NuGetizer.Tests/Builder.NuGetizer.cs b/src/NuGetizer.Tests/Builder.NuGetizer.cs index 3a246a1d..19a2b80b 100644 --- a/src/NuGetizer.Tests/Builder.NuGetizer.cs +++ b/src/NuGetizer.Tests/Builder.NuGetizer.cs @@ -11,7 +11,6 @@ using Microsoft.Build.Execution; using Microsoft.Build.Framework; using Microsoft.Build.Logging.StructuredLogger; -using NuGet.ProjectManagement; using Xunit; using Xunit.Abstractions; using Xunit.Sdk; @@ -77,12 +76,12 @@ public static TargetResult BuildProjects( } public static TargetResult BuildScenario( - string scenarioName, - object properties = null, - string projectName = null, - string target = "GetPackageContents", - ITestOutputHelper output = null, - LoggerVerbosity? verbosity = null) + string scenarioName, + object properties = null, + string projectName = null, + string target = "GetPackageContents", + ITestOutputHelper output = null, + LoggerVerbosity? verbosity = null) { var scenarioDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Scenarios", scenarioName); if (projectName != null && !Path.HasExtension(projectName)) diff --git a/src/NuGetizer.Tests/Scenarios/Scenario.props b/src/NuGetizer.Tests/Scenarios/Scenario.props index 5d5e877d..fd926819 100644 --- a/src/NuGetizer.Tests/Scenarios/Scenario.props +++ b/src/NuGetizer.Tests/Scenarios/Scenario.props @@ -27,5 +27,9 @@ $(NuGetTargetsPath)\NuGetizer.Shared.targets + + + + \ No newline at end of file diff --git a/src/NuGetizer.Tests/Scenarios/Scenario.targets b/src/NuGetizer.Tests/Scenarios/Scenario.targets index 53491801..f5b0d749 100644 --- a/src/NuGetizer.Tests/Scenarios/Scenario.targets +++ b/src/NuGetizer.Tests/Scenarios/Scenario.targets @@ -8,10 +8,6 @@ true - - - - + + + library + netstandard2.0 + true + true + true + true + + + + + + + + + \ No newline at end of file diff --git a/src/NuGetizer.Tests/given_a_library.cs b/src/NuGetizer.Tests/given_a_library.cs new file mode 100644 index 00000000..2eef3dc1 --- /dev/null +++ b/src/NuGetizer.Tests/given_a_library.cs @@ -0,0 +1,58 @@ +using System.IO; +using System.Linq; +using System.ServiceModel.Configuration; +using Microsoft.Build.Execution; +using Xunit; +using Xunit.Abstractions; + +namespace NuGetizer +{ + public class given_a_library + { + ITestOutputHelper output; + + public given_a_library(ITestOutputHelper output) + { + this.output = output; + using var disable = OpenBuildLogAttribute.Disable(); + Builder.BuildScenario(nameof(given_a_library), target: "Restore") + .AssertSuccess(output); + } + + [Fact] + public void when_pack_compile_then_excludes_generated_files() + { + var result = Builder.BuildScenario(nameof(given_a_library), + new { PackCompile = "true" }, + target: "Build,GetPackageContents,Pack"); + + Assert.True(result.BuildResult.HasResultsForTarget("GetPackageContents")); + + var items = result.BuildResult.ResultsByTarget["GetPackageContents"]; + var compile = items.Items.Where(item => item.Matches(new + { + BuildAction = "Compile", + })).ToArray(); + + Assert.Equal(2, compile.Length); + } + + [Fact] + public void when_pack_excludes_additional_items_then_contains_only_matching_files() + { + var result = Builder.BuildScenario(nameof(given_a_library), + new { PackCompile = "true", PackOnlyApi = "true" }, + target: "Build,GetPackageContents,Pack"); + + Assert.True(result.BuildResult.HasResultsForTarget("GetPackageContents")); + + var items = result.BuildResult.ResultsByTarget["GetPackageContents"]; + var compile = items.Items.Where(item => item.Matches(new + { + BuildAction = "Compile", + })).ToArray(); + + Assert.Single(compile); + } + } +} From 8c0869d7a2bd2f8315eb8b8b48b2363a2a30030c Mon Sep 17 00:00:00 2001 From: Daniel Cazzulino Date: Wed, 21 Oct 2020 17:38:54 -0300 Subject: [PATCH 2/2] If an item provides TargetPath, preserve it as relative to the PackFolder Add doc note on TargetPath and how it's used (also with Link), and make sure we don't overwrite the provided one by the user if it's present. --- README.md | 2 ++ src/NuGetizer.Tasks/NuGetizer.Inference.targets | 6 +++++- .../content-with-targetpath.txt | 0 .../library_with_content.csproj | 1 + .../given_a_library_with_content.cs | 17 +++++++++++++++++ 5 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 src/NuGetizer.Tests/Scenarios/given_a_library_with_content/content-with-targetpath.txt diff --git a/README.md b/README.md index e54bbb7b..f8b7352c 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,8 @@ If the item does **not** provide a *PackagePath*, and *Pack* is not *false*, the a. **PackFolder**: typically one of the [built-in package folders](https://github.com/NuGet/NuGet.Client/blob/dev/src/NuGet.Core/NuGet.Packaging/PackagingConstants.cs#L19), such as *build*, *lib*, etc. b. **FrameworkSpecific**: *true*/*false*, determines whether the project's target framework is used when building the final *PackagePath*. +c. **TargetPath**: optional PackFolder-relative path for the item. If not provided, the relative path of the item in the project (or its *Link* metadata) is used. + When an item specifies *FrameworkSpecific=true*, the project's target framework is added to the final package path, such as `lib\netstandard2.0\My.dll`. Since the package folder itself typically determines whether it contains framework-specific files or not, the *FrameworkSpecific* value has sensible defaults so you don't have to specify it unless you wnat to override it. The [default values from NuGetizer.props](src/NuGetizer.Tasks/NuGetizer.props) are: diff --git a/src/NuGetizer.Tasks/NuGetizer.Inference.targets b/src/NuGetizer.Tasks/NuGetizer.Inference.targets index 55a7937d..9b58f237 100644 --- a/src/NuGetizer.Tasks/NuGetizer.Inference.targets +++ b/src/NuGetizer.Tasks/NuGetizer.Inference.targets @@ -114,6 +114,7 @@ Copyright (c) .NET Foundation. All rights reserved. + @@ -173,10 +174,13 @@ Copyright (c) .NET Foundation. All rights reserved. true + + <_InferenceCandidateWithTargetPath Include="@(InferenceCandidate)" Condition="'%(ShouldPack)' == 'true' and '%(TargetPath)' != ''" /> + Condition="'%(ShouldPack)' == 'true' and '%(TargetPath)' == ''"> diff --git a/src/NuGetizer.Tests/Scenarios/given_a_library_with_content/content-with-targetpath.txt b/src/NuGetizer.Tests/Scenarios/given_a_library_with_content/content-with-targetpath.txt new file mode 100644 index 00000000..e69de29b diff --git a/src/NuGetizer.Tests/Scenarios/given_a_library_with_content/library_with_content.csproj b/src/NuGetizer.Tests/Scenarios/given_a_library_with_content/library_with_content.csproj index 3c817876..eaf66e01 100644 --- a/src/NuGetizer.Tests/Scenarios/given_a_library_with_content/library_with_content.csproj +++ b/src/NuGetizer.Tests/Scenarios/given_a_library_with_content/library_with_content.csproj @@ -46,6 +46,7 @@ + diff --git a/src/NuGetizer.Tests/given_a_library_with_content.cs b/src/NuGetizer.Tests/given_a_library_with_content.cs index 18034365..a008066d 100644 --- a/src/NuGetizer.Tests/given_a_library_with_content.cs +++ b/src/NuGetizer.Tests/given_a_library_with_content.cs @@ -366,6 +366,23 @@ public void content_with_package_path_is_included_even_with_pack_content_false() })); } + [Fact] + public void content_with_target_path_is_included_relative_to_pack_folder() + { + var result = Builder.BuildScenario(nameof(given_a_library_with_content), new + { + PackageId = "ContentPackage", + PackContent = "false" + }); + + result.AssertSuccess(output); + + Assert.Contains(result.Items, item => item.Matches(new + { + PackagePath = @"contentFiles\any\monoandroid51\relative\docs\content-with-targetpath.txt", + })); + } + #endregion #region None scenarios