diff --git a/src/Tasks.UnitTests/MSBuildInternalMessage_Tests.cs b/src/Tasks.UnitTests/MSBuildInternalMessage_Tests.cs index c03a9e2cde1..cc020da8904 100644 --- a/src/Tasks.UnitTests/MSBuildInternalMessage_Tests.cs +++ b/src/Tasks.UnitTests/MSBuildInternalMessage_Tests.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.IO; using Microsoft.Build.Evaluation; using Microsoft.Build.Shared; using Microsoft.Build.UnitTests; @@ -17,8 +18,8 @@ public class MSBuildInternalMessage_Tests public MSBuildInternalMessage_Tests(ITestOutputHelper testOutput) => _testOutput = testOutput; [Theory] - [InlineData(true, true, "CommonTarget.Prefer32BitAndPreferNativeArm64Enabled", false)] - [InlineData(false, false, "CommonTarget.PlatformIsAnyCPUAndPreferNativeArm64Enabled", true, new[] { "Release" })] + [InlineData(true, true, "CommonSdk.Prefer32BitAndPreferNativeArm64Enabled", false)] + [InlineData(false, false, "CommonSdk.PlatformIsAnyCPUAndPreferNativeArm64Enabled", true, new[] { "Release" })] public void E2EScenarioTests(bool prefer32, bool isPlatformAnyCpu, string expectedResourceName, bool isNetWarningExpected, string[]? formatArgs = null) { using (TestEnvironment env = TestEnvironment.Create()) @@ -59,5 +60,233 @@ public void E2EScenarioTests(bool prefer32, bool isPlatformAnyCpu, string expect } } } + + [Theory] + [InlineData(true, "CommonSdk.BaseIntermediateOutputPathMismatchWarning")] + [InlineData(false, "CommonSdk.MSBuildProjectExtensionsPathModifiedAfterUse")] + + public void BaseIntermediateOutputPathMisMatchWarning(bool isInitialMSBuildProjectExtensionsPathEmpty, string expectedResourceName) + { + using (TestEnvironment env = TestEnvironment.Create()) + { + var outputPath = env.CreateFolder().Path; + string projectContent = $""" + + + + + true + <_InitialMSBuildProjectExtensionsPath>{(isInitialMSBuildProjectExtensionsPathEmpty ? "" : "obj")} + + obj\Debug\ + + + + + """; + + var projectFile = env.CreateFile(env.CreateFolder(), "test.csproj", projectContent).Path; + Project project = ObjectModelHelpers.LoadProjectFileInTempProjectDirectory(projectFile, touchProject: false); + + string expectedBuildMessage = ResourceUtilities.FormatResourceStringStripCodeAndKeyword(expectedResourceName); + MockLogger logger = new MockLogger(_testOutput); + + project.Build(logger); + if (!isInitialMSBuildProjectExtensionsPathEmpty) + { + logger.Errors[0].RawMessage.ShouldBe(expectedBuildMessage); + } + else + { + logger.Warnings[0].RawMessage.ShouldBe(expectedBuildMessage); + } + } + } + + [Theory] + [InlineData("SetGenerateManifests", "CommonSdk.GenerateManifestsOnlyForExe", false)] + [InlineData("SetGenerateManifests", "CommonSdk.SigningKeyRequired", true)] + [InlineData("_DeploymentUnpublishable", "CommonSdk.DeploymentUnpublishable")] + [InlineData("Run", "CommonSdk.RunTargetDependsOnMessage")] + [InlineData("GetTargetFrameworks", "CommonSdk.CrossTargetingGetTargetFrameworks")] + [InlineData("ResolveProjectReferences", "CommonSdk.NonExistentProjectReference")] + [InlineData("ResolveProjectReferences", "CommonSdk.NonExistentProjectReference", true, false)] + public void RunTargetExtError(string targetName, string expectedResourceName, bool outputTypeIsExe = true, bool errorOnMissingProjectReference = true) + { + using (TestEnvironment env = TestEnvironment.Create()) + { + var outputPath = env.CreateFolder().Path; + string projectContent = $""" + + + + + .txt + bin + {(outputTypeIsExe ? "" : "txt")} + <_DeploymentSignClickOnceManifests>true + + + netcoreapp3.1;net6.0;net7.0 + {errorOnMissingProjectReference} + + + + + + + + + + """; + + var projectFile = env.CreateFile(env.CreateFolder(), "test.csproj", projectContent).Path; + Project project = ObjectModelHelpers.LoadProjectFileInTempProjectDirectory(projectFile, touchProject: false); + + MockLogger logger = new MockLogger(_testOutput); + + string expectedBuildMessage = ResourceUtilities.FormatResourceStringStripCodeAndKeyword(expectedResourceName); + + project.Build(logger); + if (expectedResourceName == "CommonSdk.DeploymentUnpublishable") + { + logger.FullLog.Contains(expectedBuildMessage); + } + else if (expectedResourceName == "CommonSdk.RunTargetDependsOnMessage") + { + var targetPathParameter = expectedResourceName == "CommonSdk.DeploymentUnpublishable" ? "" : Path.Combine(project.DirectoryPath, "bin", "test.txt"); + expectedBuildMessage = ResourceUtilities.FormatResourceStringStripCodeAndKeyword(expectedResourceName, targetPathParameter); + logger.Errors[0].RawMessage.ShouldBe(expectedBuildMessage); + } + else if (expectedResourceName == "CommonSdk.NonExistentProjectReference") + { + expectedBuildMessage = ResourceUtilities.FormatResourceStringStripCodeAndKeyword(expectedResourceName, "NonExistent.csproj"); + if (errorOnMissingProjectReference) + { + logger.Errors[0].RawMessage.ShouldBe(expectedBuildMessage); + } + else + { + logger.Warnings[0].RawMessage.ShouldBe(expectedBuildMessage); + } + } + else + { + logger.Errors[0].RawMessage.ShouldBe(expectedBuildMessage); + } + } + } + + /// + /// SkipInvalidConfigurations is true, the output is warning, otherwise is error. + /// BuildingInsideVisualStudio is true, the resourceName is CommonSdk.InvalidConfigurationTextWhenBuildingInsideVisualStudio, otherwise is CommonSdk.InvalidConfigurationTextWhenBuildingOutsideVisualStudio + /// + /// + /// + /// + [Theory] + [InlineData("CommonSdk.InvalidConfigurationTextWhenBuildingInsideVisualStudio", false, true)] + [InlineData("CommonSdk.InvalidConfigurationTextWhenBuildingOutsideVisualStudio", true, false)] + [InlineData("CommonSdk.InvalidConfigurationTextWhenBuildingOutsideVisualStudio", false, false)] + [InlineData("CommonSdk.InvalidConfigurationTextWhenBuildingInsideVisualStudio", true, true)] + public void CheckForInvalidConfigurationAndPlatformTargetMessage(string expectedResourceName, bool skipInvalidConfigurations, bool buildingInsideVisualStudio) + { + using (TestEnvironment env = TestEnvironment.Create()) + { + var outputPath = env.CreateFolder().Path; + var fileName = "test.csproj"; + var configuration = "Release"; + var platform = "Release"; + string projectContent = $""" + + + + + {skipInvalidConfigurations} + {buildingInsideVisualStudio} + false + <_OutputPathWasMissing>true + {configuration} + {platform} + + + + + + """; + + var projectFile = env.CreateFile(env.CreateFolder(), fileName, projectContent).Path; + Project project = ObjectModelHelpers.LoadProjectFileInTempProjectDirectory(projectFile, touchProject: false); + + MockLogger logger = new MockLogger(_testOutput); + + string expectedBuildMessage = ResourceUtilities.FormatResourceStringStripCodeAndKeyword(expectedResourceName, fileName, configuration, platform); + + project.Build(logger); + if (skipInvalidConfigurations) + { + logger.Warnings[0].RawMessage.ShouldBe(expectedBuildMessage); + } + else + { + logger.Errors[0].RawMessage.ShouldBe(expectedBuildMessage); + } + } + } + + [Theory] + [InlineData("MSB9000", "ResxWithNoCulture", "SplitResourcesByCulture", "CommonSdk.SplitResourcesByCultureEmbeddedResourceMessage"),] + [InlineData("MSB9001", "ResxWithCulture", "SplitResourcesByCulture", "CommonSdk.SplitResourcesByCultureEmbeddedResourceMessage")] + [InlineData("MSB9002", "NonResxWithCulture", "SplitResourcesByCulture", "CommonSdk.SplitResourcesByCultureEmbeddedResourceMessage")] + [InlineData("MSB9003", "NonResxWithNoCulture", "SplitResourcesByCulture", "CommonSdk.SplitResourcesByCultureEmbeddedResourceMessage")] + [InlineData("MSB9004", "ManifestResourceWithNoCulture", "_GenerateCompileInputs", "CommonSdk.ManifestResourceWithNoCultureWarning")] + [InlineData("MSB9005", "ManifestNonResxWithNoCultureOnDisk", "_GenerateCompileInputs", "CommonSdk.ManifestResourceWithNoCultureWarning")] + [InlineData("MSB9006", "ManifestResourceWithCulture", "_GenerateSatelliteAssemblyInputs", "CommonSdk.ManifestResourceWithNoCultureWarning")] + [InlineData("MSB9007", "ManifestNonResxWithCultureOnDisk", "_GenerateSatelliteAssemblyInputs", "CommonSdk.ManifestResourceWithNoCultureWarning")] + public void ResourcesByCultureWarningMessage(string warningNumber, string itemName, string targetName, string resourceName) + { + using (TestEnvironment env = TestEnvironment.Create()) + { + var outputPath = env.CreateFolder().Path; + string projectContent = $""" + + + + + <{itemName} Include="Value1" /> + + + + + """; + + var projectFile = env.CreateFile(env.CreateFolder(), "test.csproj", projectContent).Path; + Project project = ObjectModelHelpers.LoadProjectFileInTempProjectDirectory(projectFile, touchProject: false); + + MockLogger logger = new MockLogger(_testOutput); + object[] args = [warningNumber, itemName]; + if (warningNumber == "MSB9004") + { + args = [warningNumber, itemName, "false", "Resx"]; + } + else if (warningNumber == "MSB9005") + { + args = [warningNumber, itemName, "false", "Non-Resx"]; + } + else if (warningNumber == "MSB9006") + { + args = [warningNumber, itemName, "true", "Resx"]; + } + else if (warningNumber == "MSB9007") + { + args = [warningNumber, itemName, "true", "Non-Resx"]; + } + + string expectedBuildMessage = ResourceUtilities.FormatResourceStringStripCodeAndKeyword(resourceName, args); + + project.Build(logger); + logger.Warnings[0].RawMessage.ShouldBe(expectedBuildMessage); + } + } } } diff --git a/src/Tasks/MSBuildInternalMessage.cs b/src/Tasks/MSBuildInternalMessage.cs index 9e54fa38c34..3ba6368b347 100644 --- a/src/Tasks/MSBuildInternalMessage.cs +++ b/src/Tasks/MSBuildInternalMessage.cs @@ -76,7 +76,7 @@ public override bool Execute() } } - Log.LogErrorFromResources("CommonTarget.SpecifiedSeverityDoesNotExist", Severity); + Log.LogErrorFromResources("CommonSdk.SpecifiedSeverityDoesNotExist", Severity); return !Log.HasLoggedErrors; } diff --git a/src/Tasks/Microsoft.Common.CurrentVersion.targets b/src/Tasks/Microsoft.Common.CurrentVersion.targets index b7e42801af8..ac8926db8f8 100644 --- a/src/Tasks/Microsoft.Common.CurrentVersion.targets +++ b/src/Tasks/Microsoft.Common.CurrentVersion.targets @@ -202,8 +202,8 @@ Copyright (C) Microsoft Corporation. All rights reserved. we're in legacy mode and we shall assume the current Configuration/Platform combination as invalid. Whether this is considered an error or a warning depends on the value of $(SkipInvalidConfigurations). --> - <_InvalidConfigurationError Condition=" '$(SkipInvalidConfigurations)' != 'true' ">true - <_InvalidConfigurationWarning Condition=" '$(SkipInvalidConfigurations)' == 'true' ">true + <_InvalidConfigurationMessageSeverity Condition=" '$(SkipInvalidConfigurations)' == 'true' ">Warning + <_InvalidConfigurationMessageSeverity Condition=" '$(SkipInvalidConfigurations)' != 'true' ">Error - - - + + + - + - + - - - + + + <_NonExistentProjectReferenceSeverity Condition="'@(ProjectReferenceWithConfiguration)' != '' and '@(_MSBuildProjectReferenceNonexistent)' != '' and '$(ErrorOnMissingProjectReference)' != 'True'">Warning + <_NonExistentProjectReferenceSeverity Condition="'@(ProjectReferenceWithConfiguration)' != '' and '@(_MSBuildProjectReferenceNonexistent)' != '' and '$(ErrorOnMissingProjectReference)' == 'True'">Error + + @@ -3260,10 +3271,10 @@ Copyright (C) Microsoft Corporation. All rights reserved. false - - - - + + + + <_LicxFile Include="@(EmbeddedResource)" Condition="'%(Extension)'=='.licx'"/> @@ -3637,8 +3648,16 @@ Copyright (C) Microsoft Corporation. All rights reserved. --> - - + + @@ -3988,8 +4007,16 @@ Copyright (C) Microsoft Corporation. All rights reserved. --> - - + + @@ -5983,7 +6010,7 @@ Copyright (C) Microsoft Corporation. All rights reserved. - + @@ -5997,8 +6024,8 @@ Copyright (C) Microsoft Corporation. All rights reserved. - - + + true @@ -6603,7 +6630,7 @@ Copyright (C) Microsoft Corporation. All rights reserved. Returns="@(SDKRedistOutputGroupOutput)" DependsOnTargets="$(SDKRedistOutputGroupDependsOn)"> - + diff --git a/src/Tasks/Resources/Strings.resx b/src/Tasks/Resources/Strings.resx index 47a18ddf8a9..ebab7e62c9a 100644 --- a/src/Tasks/Resources/Strings.resx +++ b/src/Tasks/Resources/Strings.resx @@ -3038,23 +3038,79 @@ - + MSB9901: The specified severity is not relevant: '{0}' for the message: '{1}'. {StrBegin="MSB9901: "} - + MSB9902: Prefer32Bit and PreferNativeArm64 options are mutually exclusive. Please enable only one. {StrBegin="MSB9902: "} - + MSB9903: PreferNativeArm64 requires a Win32 application manifest and is mutually exclusive with NoWin32Manifest. {StrBegin="MSB9903: "} - + MSB9904: When PreferNativeArm64 is enabled, ensure that the Platform is set to AnyCPU. Current Platform: {0}. {StrBegin="MSB9904: "} + + MSB3539: The value of the property "BaseIntermediateOutputPath" was modified after it was used by MSBuild which can lead to unexpected build results. Tools such as NuGet will write outputs to the path specified by the "MSBuildProjectExtensionsPath" instead. To set this property, you must do so before Microsoft.Common.props is imported, for example by using Directory.Build.props. For more information, please visit https://go.microsoft.com/fwlink/?linkid=869650" + {StrBegin="MSB3539: "} + + + + MSB3540: The value of the property "MSBuildProjectExtensionsPath" was modified after it was used by MSBuild which can lead to unexpected build results. To set this property, you must do so before Microsoft.Common.props is imported, for example by using Directory.Build.props. For more information, please visit https://go.microsoft.com/fwlink/?linkid=869650 + {StrBegin="MSB3540: "} + + + + The BaseOutputPath/OutputPath property is not set for project '{0}'. Please check to make sure that you have specified a valid combination of Configuration and Platform for this project. Configuration='{1}' Platform='{2}'. This error may also appear if some other project is trying to follow a project-to-project reference to this project, this project has been unloaded or is not included in the solution, and the referencing project does not build using the same or an equivalent Configuration or Platform. + LOCALIZATION: Do not localize the words "BaseOutputPath/OutputPath", "Configuration" and "Platform" + + + + The BaseOutputPath/OutputPath property is not set for project '{0}'. Please check to make sure that you have specified a valid combination of Configuration and Platform for this project. Configuration='{1}' Platform='{2}'. You may be seeing this message because you are trying to build a project without a solution file, and have specified a non-default Configuration or Platform that doesn't exist for this project. + LOCALIZATION: Do not localize the words "BaseOutputPath/OutputPath", "Configuration" and "Platform" + + + + {0}: {1} item type is deprecated. Emit EmbeddedResource items instead, with metadata WithCulture='{2}', Type='{3}', and optional LogicalName. + + + + The {0} must end with a trailing slash. + + + + Skipping unpublishable project. + + + + Publish is only valid for 'Windows Application' or 'Console Application' project types. + + + + A signing key is required in order to publish this project. Please specify a ManifestKeyFile or ManifestCertificateThumbprint value. Publishing from Visual Studio will automatically configure a signing key for this project. + + + + Cannot run '{0}' because project output type is not '.exe' + + + + Internal MSBuild error: Non-CrossTargeting GetTargetFrameworks target should not be used in cross targeting (outer) build + + + + {0}: {1} item type is deprecated. Use EmbeddedResource items instead. + + + + MSB9008: The referenced project {0} does not exist. + +