diff --git a/src/Cli/Microsoft.DotNet.Cli.Utils/MSBuildPropertyParser.cs b/src/Cli/Microsoft.DotNet.Cli.Utils/MSBuildPropertyParser.cs index 399ceaecafd1..451560f95415 100644 --- a/src/Cli/Microsoft.DotNet.Cli.Utils/MSBuildPropertyParser.cs +++ b/src/Cli/Microsoft.DotNet.Cli.Utils/MSBuildPropertyParser.cs @@ -10,6 +10,10 @@ namespace Microsoft.DotNet.Cli.Utils; +/// +/// Parses property key value pairs that have already been forwarded through the PropertiesOption class. +/// Does not parse -p and etc. formats, (this is done by PropertiesOption) but does parse property values separated by =, ;, and using quotes. +/// public static class MSBuildPropertyParser { public static IEnumerable<(string key, string value)> ParseProperties(string input) { var currentPos = 0; diff --git a/src/Cli/dotnet/ReleasePropertyProjectLocator.cs b/src/Cli/dotnet/ReleasePropertyProjectLocator.cs index 52aac61ab583..e16b2b3c7890 100644 --- a/src/Cli/dotnet/ReleasePropertyProjectLocator.cs +++ b/src/Cli/dotnet/ReleasePropertyProjectLocator.cs @@ -188,13 +188,15 @@ private bool IsValidProjectFilePath(string path) private Dictionary GetGlobalPropertiesFromUserArgs(ParseResult parseResult) { Dictionary globalProperties = new Dictionary(StringComparer.OrdinalIgnoreCase); - string[] globalPropEnumerable = parseResult.GetValueForOption(CommonOptions.PropertiesOption); - foreach (var keyEqVal in globalPropEnumerable) + foreach (var keyEqValString in globalPropEnumerable) { - string[] keyValuePair = keyEqVal.Split("=", 2); - globalProperties[keyValuePair[0]] = keyValuePair[1]; + var propertyPairs = MSBuildPropertyParser.ParseProperties(keyEqValString); + foreach (var propertyKeyValue in propertyPairs) + { + globalProperties[propertyKeyValue.key] = propertyKeyValue.value; + } } return globalProperties; } diff --git a/src/Tests/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAHelloWorldProject.cs b/src/Tests/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAHelloWorldProject.cs index 978dc4677f8a..4637a9158f6b 100644 --- a/src/Tests/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAHelloWorldProject.cs +++ b/src/Tests/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAHelloWorldProject.cs @@ -4,6 +4,7 @@ using System; using System.IO; using System.Linq; +using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security.Cryptography; @@ -688,11 +689,13 @@ public void PublishRelease_does_not_override_custom_Configuration_on_proj_and_lo [InlineData("-property:Configuration=Debug")] [InlineData("--property:Configuration=Debug")] [InlineData("/p:Configuration=Debug")] + [InlineData("-p:_IsPublishing=true;Configuration=Debug")] + [InlineData("-p:_IsPublishing=true;Configuration=Debug;")] [InlineData("/property:Configuration=Debug")] public void PublishRelease_does_not_override_Configuration_property_across_formats(string configOpt) { var helloWorldAsset = _testAssetsManager - .CopyTestAsset("HelloWorld", $"PublishReleaseHelloWorldCsProjConfigPropOverride{configOpt}") + .CopyTestAsset("HelloWorld", identifier: configOpt) .WithSource() .WithTargetFramework(ToolsetInfo.CurrentTargetFramework) .WithProjectChanges(project => @@ -702,24 +705,45 @@ public void PublishRelease_does_not_override_Configuration_property_across_forma propertyGroup.Add(new XElement(ns + "PublishRelease", "true")); }); - new BuildCommand(helloWorldAsset) - .Execute(configOpt) - .Should() - .Pass(); - - var publishCommand = new DotnetPublishCommand(Log, helloWorldAsset.TestRoot); - - publishCommand - .Execute(configOpt) - .Should() - .Pass().And.NotHaveStdErr(); + new DotnetPublishCommand(Log, helloWorldAsset.TestRoot) + .Execute(configOpt) + .Should() + .Pass().And.NotHaveStdErr(); - var expectedAssetPath = System.IO.Path.Combine(helloWorldAsset.Path, "bin", "Debug", ToolsetInfo.CurrentTargetFramework, "HelloWorld.dll"); + var expectedAssetPath = Path.Combine(helloWorldAsset.Path, "bin", "Debug", ToolsetInfo.CurrentTargetFramework, "HelloWorld.dll"); Assert.True(File.Exists(expectedAssetPath)); - var releaseAssetPath = System.IO.Path.Combine(helloWorldAsset.Path, "bin", "Release", ToolsetInfo.CurrentTargetFramework, "HelloWorld.dll"); + var releaseAssetPath = Path.Combine(helloWorldAsset.Path, "bin", "Release", ToolsetInfo.CurrentTargetFramework, "HelloWorld.dll"); Assert.False(File.Exists(releaseAssetPath)); // build will produce a debug asset, need to make sure this doesn't exist either. } + [Theory] + [InlineData("")] + [InlineData("=")] + public void PublishRelease_does_recognize_undefined_property(string propertySuffix) + { + string tfm = ToolsetInfo.CurrentTargetFramework; + var testProject = new TestProject() + { + IsExe = true, + TargetFrameworks = tfm + }; + + testProject.RecordProperties("SelfContained"); + testProject.RecordProperties("PublishAot"); + + var testAsset = _testAssetsManager.CreateTestProject(testProject); + new DotnetPublishCommand(Log) + .WithWorkingDirectory(Path.Combine(testAsset.TestRoot, MethodBase.GetCurrentMethod().Name)) + .Execute(("-p:SelfContained" + propertySuffix)) + .Should() + .Pass(); + + var properties = testProject.GetPropertyValues(testAsset.TestRoot, targetFramework: tfm); + + Assert.Equal("", properties["SelfContained"]); + Assert.Equal("", properties["PublishAot"]); + } + [Fact] public void PublishRelease_does_not_override_Configuration_option() {