f9b939fe89
This commit ensures that any `/property` option's value is surrounded by quotes to allow MSBuild to properly interpret special characters like semicolons. Users familiar with MSBuild expect `/property:Name="Value"` to handle semicolons. However, since `dotnet` parses the command line first, the quotes get processed by its command line parser. This results in `/property:Name=Value` being passed to MSBuild, which will not parse a "Value" containing a semicolon correctly. Since it is safe to always quote the property value for this option, this fix simply ensures that the value is surrounded by quotes. This fixes the issue for all commands that forward arguments to MSBuild. Fixes #7791.
121 lines
5.8 KiB
C#
121 lines
5.8 KiB
C#
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
|
|
using System;
|
|
using FluentAssertions;
|
|
using System.Linq;
|
|
using Microsoft.DotNet.Cli.CommandLine;
|
|
using Microsoft.DotNet.Tools.Publish;
|
|
using Xunit;
|
|
using Xunit.Abstractions;
|
|
|
|
namespace Microsoft.DotNet.Cli.MSBuild.Tests
|
|
{
|
|
public class GivenDotnetPublishInvocation
|
|
{
|
|
private readonly ITestOutputHelper output;
|
|
|
|
public GivenDotnetPublishInvocation(ITestOutputHelper output)
|
|
{
|
|
this.output = output;
|
|
}
|
|
|
|
const string ExpectedPrefix = "exec <msbuildpath> -maxcpucount -verbosity:m";
|
|
|
|
[Theory]
|
|
[InlineData(new string[] { }, "")]
|
|
[InlineData(new string[] { "-r", "<rid>" }, @"-property:RuntimeIdentifier=\""<rid>\""")]
|
|
[InlineData(new string[] { "--runtime", "<rid>" }, @"-property:RuntimeIdentifier=\""<rid>\""")]
|
|
[InlineData(new string[] { "-o", "<publishdir>" }, @"-property:PublishDir=\""<publishdir>\""")]
|
|
[InlineData(new string[] { "--output", "<publishdir>" }, @"-property:PublishDir=\""<publishdir>\""")]
|
|
[InlineData(new string[] { "-c", "<config>" }, @"-property:Configuration=\""<config>\""")]
|
|
[InlineData(new string[] { "--configuration", "<config>" }, @"-property:Configuration=\""<config>\""")]
|
|
[InlineData(new string[] { "--version-suffix", "<versionsuffix>" }, @"-property:VersionSuffix=\""<versionsuffix>\""")]
|
|
[InlineData(new string[] { "--manifest", "<manifestfiles>" }, @"-property:TargetManifestFiles=\""<manifestfiles>\""")]
|
|
[InlineData(new string[] { "-v", "minimal" }, "-verbosity:minimal")]
|
|
[InlineData(new string[] { "--verbosity", "minimal" }, "-verbosity:minimal")]
|
|
[InlineData(new string[] { "<project>" }, "<project>")]
|
|
[InlineData(new string[] { "<project>", "<extra-args>" }, "<project> <extra-args>")]
|
|
public void MsbuildInvocationIsCorrect(string[] args, string expectedAdditionalArgs)
|
|
{
|
|
expectedAdditionalArgs = (string.IsNullOrEmpty(expectedAdditionalArgs) ? "" : $" {expectedAdditionalArgs}");
|
|
|
|
var msbuildPath = "<msbuildpath>";
|
|
var command = PublishCommand.FromArgs(args, msbuildPath);
|
|
|
|
command.SeparateRestoreCommand
|
|
.Should()
|
|
.BeNull();
|
|
|
|
command.GetProcessStartInfo()
|
|
.Arguments.Should()
|
|
.Be($"{ExpectedPrefix} -restore -target:Publish{expectedAdditionalArgs}");
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(new string[] { "-f", "<tfm>" }, @"-property:TargetFramework=\""<tfm>\""")]
|
|
[InlineData(new string[] { "--framework", "<tfm>" }, @"-property:TargetFramework=\""<tfm>\""")]
|
|
public void MsbuildInvocationIsCorrectForSeparateRestore(string[] args, string expectedAdditionalArgs)
|
|
{
|
|
expectedAdditionalArgs = (string.IsNullOrEmpty(expectedAdditionalArgs) ? "" : $" {expectedAdditionalArgs}");
|
|
|
|
var msbuildPath = "<msbuildpath>";
|
|
var command = PublishCommand.FromArgs(args, msbuildPath);
|
|
|
|
command.SeparateRestoreCommand
|
|
.GetProcessStartInfo()
|
|
.Arguments.Should()
|
|
.Be($"{ExpectedPrefix} -target:Restore");
|
|
|
|
command.GetProcessStartInfo()
|
|
.Arguments.Should()
|
|
.Be($"{ExpectedPrefix} -nologo -target:Publish{expectedAdditionalArgs}");
|
|
}
|
|
|
|
[Fact]
|
|
public void MsbuildInvocationIsCorrectForNoBuild()
|
|
{
|
|
var msbuildPath = "<msbuildpath>";
|
|
var command = PublishCommand.FromArgs(new[] { "--no-build" }, msbuildPath);
|
|
|
|
command.SeparateRestoreCommand
|
|
.Should()
|
|
.BeNull();
|
|
|
|
// NOTE --no-build implies no-restore hence no -restore argument to msbuild below.
|
|
command.GetProcessStartInfo()
|
|
.Arguments
|
|
.Should()
|
|
.Be($"{ExpectedPrefix} -target:Publish -property:NoBuild=\\\"true\\\"");
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(new string[] { }, "")]
|
|
[InlineData(new string[] { "-f", "<tfm>" }, "-property:TargetFramework=<tfm>")]
|
|
[InlineData(new string[] { "--framework", "<tfm>" }, "-property:TargetFramework=<tfm>")]
|
|
[InlineData(new string[] { "-r", "<rid>" }, "-property:RuntimeIdentifier=<rid>")]
|
|
[InlineData(new string[] { "--runtime", "<rid>" }, "-property:RuntimeIdentifier=<rid>")]
|
|
[InlineData(new string[] { "-o", "<publishdir>" }, "-property:PublishDir=<publishdir>")]
|
|
[InlineData(new string[] { "--output", "<publishdir>" }, "-property:PublishDir=<publishdir>")]
|
|
[InlineData(new string[] { "-c", "<config>" }, "-property:Configuration=<config>")]
|
|
[InlineData(new string[] { "--configuration", "<config>" }, "-property:Configuration=<config>")]
|
|
[InlineData(new string[] { "--version-suffix", "<versionsuffix>" }, "-property:VersionSuffix=<versionsuffix>")]
|
|
[InlineData(new string[] { "--manifest", "<manifestfiles>" }, "-property:TargetManifestFiles=<manifestfiles>")]
|
|
[InlineData(new string[] { "-v", "minimal" }, "-verbosity:minimal")]
|
|
[InlineData(new string[] { "--verbosity", "minimal" }, "-verbosity:minimal")]
|
|
[InlineData(new string[] { "--no-build" }, "-property:NoBuild=true")]
|
|
public void OptionForwardingIsCorrect(string[] args, string expectedAdditionalArgs)
|
|
{
|
|
var expectedArgs = expectedAdditionalArgs.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
|
|
|
var parser = Parser.Instance;
|
|
|
|
var result = parser.ParseFrom("dotnet publish", args);
|
|
|
|
result["dotnet"]["publish"]
|
|
.OptionValuesToBeForwarded()
|
|
.Should()
|
|
.BeEquivalentTo(expectedArgs);
|
|
}
|
|
}
|
|
}
|