diff --git a/MSBuild.sln b/MSBuild.sln index 63edfa67df2..da041af91bd 100644 --- a/MSBuild.sln +++ b/MSBuild.sln @@ -80,6 +80,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MSBuild.VSSetup.Arm64", "sr EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Build.Analyzers", "src\Analyzers\Microsoft.Build.Analyzers.csproj", "{512E01F7-2899-433B-93E2-D63B43AF0420}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Build.Analyzers.UnitTests", "src\Analyzers.UnitTests\Microsoft.Build.Analyzers.UnitTests.csproj", "{B18BAE17-D78F-4F89-B7A4-808C05E64D73}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1384,6 +1386,46 @@ Global {512E01F7-2899-433B-93E2-D63B43AF0420}.Release-MONO|x64.Build.0 = Release-MONO|x64 {512E01F7-2899-433B-93E2-D63B43AF0420}.Release-MONO|x86.ActiveCfg = Release-MONO|Any CPU {512E01F7-2899-433B-93E2-D63B43AF0420}.Release-MONO|x86.Build.0 = Release-MONO|Any CPU + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Debug|ARM64.ActiveCfg = Debug|arm64 + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Debug|ARM64.Build.0 = Debug|arm64 + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Debug|x64.ActiveCfg = Debug|x64 + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Debug|x64.Build.0 = Debug|x64 + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Debug|x86.ActiveCfg = Debug|Any CPU + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Debug|x86.Build.0 = Debug|Any CPU + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Debug-MONO|Any CPU.ActiveCfg = Debug-MONO|Any CPU + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Debug-MONO|Any CPU.Build.0 = Debug-MONO|Any CPU + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Debug-MONO|ARM64.ActiveCfg = Debug-MONO|arm64 + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Debug-MONO|ARM64.Build.0 = Debug-MONO|arm64 + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Debug-MONO|x64.ActiveCfg = Debug-MONO|x64 + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Debug-MONO|x64.Build.0 = Debug-MONO|x64 + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Debug-MONO|x86.ActiveCfg = Debug-MONO|Any CPU + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Debug-MONO|x86.Build.0 = Debug-MONO|Any CPU + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.MachineIndependent|Any CPU.ActiveCfg = MachineIndependent|Any CPU + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.MachineIndependent|Any CPU.Build.0 = MachineIndependent|Any CPU + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.MachineIndependent|ARM64.ActiveCfg = MachineIndependent|arm64 + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.MachineIndependent|ARM64.Build.0 = MachineIndependent|arm64 + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.MachineIndependent|x64.ActiveCfg = MachineIndependent|x64 + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.MachineIndependent|x64.Build.0 = MachineIndependent|x64 + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.MachineIndependent|x86.ActiveCfg = MachineIndependent|Any CPU + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.MachineIndependent|x86.Build.0 = MachineIndependent|Any CPU + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Release|Any CPU.Build.0 = Release|Any CPU + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Release|ARM64.ActiveCfg = Release|arm64 + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Release|ARM64.Build.0 = Release|arm64 + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Release|x64.ActiveCfg = Release|x64 + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Release|x64.Build.0 = Release|x64 + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Release|x86.ActiveCfg = Release|Any CPU + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Release|x86.Build.0 = Release|Any CPU + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Release-MONO|Any CPU.ActiveCfg = Release-MONO|Any CPU + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Release-MONO|Any CPU.Build.0 = Release-MONO|Any CPU + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Release-MONO|ARM64.ActiveCfg = Release-MONO|arm64 + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Release-MONO|ARM64.Build.0 = Release-MONO|arm64 + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Release-MONO|x64.ActiveCfg = Release-MONO|x64 + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Release-MONO|x64.Build.0 = Release-MONO|x64 + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Release-MONO|x86.ActiveCfg = Release-MONO|Any CPU + {B18BAE17-D78F-4F89-B7A4-808C05E64D73}.Release-MONO|x86.Build.0 = Release-MONO|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/eng/BootStrapMSBuild.props b/eng/BootStrapMSBuild.props new file mode 100644 index 00000000000..e70bcb3489d --- /dev/null +++ b/eng/BootStrapMSBuild.props @@ -0,0 +1,21 @@ + + + + + + $(ArtifactsBinDir)bootstrap\ + $(BootstrapDestination)$(Platform)\ + $(BootstrapDestination)$(TargetFramework.ToLowerInvariant())\MSBuild\ + + + + $(BootstrapDestination)$(TargetMSBuildToolsVersion)\Bin + + + + $(BootstrapDestination) + + diff --git a/eng/BootStrapMSBuild.targets b/eng/BootStrapMSBuild.targets index e6fee0282f8..395a84d09b3 100644 --- a/eng/BootStrapMSBuild.targets +++ b/eng/BootStrapMSBuild.targets @@ -1,5 +1,7 @@ + + - $(ArtifactsBinDir)bootstrap\ - $(BootstrapDestination)$(Platform)\ - $(BootstrapDestination)$(TargetFramework.ToLowerInvariant())\MSBuild\ - BootstrapFull BootstrapNetCore diff --git a/src/Analyzers.UnitTests/AssemblyInfo.cs b/src/Analyzers.UnitTests/AssemblyInfo.cs new file mode 100644 index 00000000000..0f119a6530d --- /dev/null +++ b/src/Analyzers.UnitTests/AssemblyInfo.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +global using NativeMethodsShared = Microsoft.Build.Framework.NativeMethods; + +namespace Microsoft.Build.Analyzers.UnitTests; + +[System.AttributeUsage(System.AttributeTargets.Assembly)] +internal sealed class BootstrapLocationAttribute(string bootstrapRoot, string bootstrapMsbuildBinaryLocation) + : System.Attribute +{ + public string BootstrapRoot { get; } = bootstrapRoot; + public string BootstrapMsbuildBinaryLocation { get; } = bootstrapMsbuildBinaryLocation; +} diff --git a/src/Analyzers.UnitTests/BootstrapRunner.cs b/src/Analyzers.UnitTests/BootstrapRunner.cs new file mode 100644 index 00000000000..540abc8ac63 --- /dev/null +++ b/src/Analyzers.UnitTests/BootstrapRunner.cs @@ -0,0 +1,37 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Build.UnitTests.Shared; +using Xunit.Abstractions; + +namespace Microsoft.Build.Analyzers.UnitTests +{ + internal static class BootstrapRunner + { + // This should ideally be part of RunnerUtilities - however then we'd need to enforce + // all test projects to import the BootStrapMSBuild.props file and declare the BootstrapLocationAttribute. + // Better solution would be to have a single test utility project - instead of linked code files. + public static string ExecBootstrapedMSBuild(string msbuildParameters, out bool successfulExit, bool shellExecute = false, ITestOutputHelper outputHelper = null) + { + var binaryFolder = Assembly.GetExecutingAssembly() + .GetCustomAttribute()! + .BootstrapMsbuildBinaryLocation; + +#if NET + string pathToExecutable = EnvironmentProvider.GetDotnetExePath()!; + msbuildParameters = Path.Combine(binaryFolder, "msbuild.dll") + " " + msbuildParameters; +#else + string pathToExecutable = + Path.Combine(binaryFolder, "msbuild.exe"); +#endif + return RunnerUtilities.RunProcessAndGetOutput(pathToExecutable, msbuildParameters, out successfulExit, shellExecute, outputHelper); + } + } +} diff --git a/src/Build.UnitTests/Analyzers/EndToEndTests.cs b/src/Analyzers.UnitTests/EndToEndTests.cs similarity index 94% rename from src/Build.UnitTests/Analyzers/EndToEndTests.cs rename to src/Analyzers.UnitTests/EndToEndTests.cs index 79ecd1addc9..76a5479ebaa 100644 --- a/src/Build.UnitTests/Analyzers/EndToEndTests.cs +++ b/src/Analyzers.UnitTests/EndToEndTests.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Reflection; using System.Text; using System.Threading.Tasks; using Microsoft.Build.UnitTests; @@ -13,7 +14,7 @@ using Xunit; using Xunit.Abstractions; -namespace Microsoft.Build.Engine.UnitTests.Analyzers +namespace Microsoft.Build.Analyzers.UnitTests { public class EndToEndTests { @@ -27,8 +28,6 @@ public EndToEndTests(ITestOutputHelper output) } [Fact] - // WARNING!: this test is using a bootstrap - so a build.cmd needs to be run prior this test can properly capture the - // changes in the production code public void SampleAnalyzerIntegrationTest() { using (TestEnvironment env = TestEnvironment.Create()) @@ -113,7 +112,7 @@ public void SampleAnalyzerIntegrationTest() // env.SetEnvironmentVariable("MSBUILDNOINPROCNODE", "1"); env.SetEnvironmentVariable("MSBUILDLOGPROPERTIESANDITEMSAFTEREVALUATION", "1"); // string output = RunnerUtilities.ExecMSBuild($"{projectFile.Path} /m:1 -nr:False", out bool success); - string output = RunnerUtilities.ExecBootstrapedMSBuild($"{projectFile.Path} /m:1 -nr:False -restore", out bool success); + string output = BootstrapRunner.ExecBootstrapedMSBuild($"{projectFile.Path} /m:1 -nr:False -restore", out bool success); _env.Output.WriteLine(output); success.ShouldBeTrue(); // The conflicting outputs warning appears diff --git a/src/Analyzers.UnitTests/Microsoft.Build.Analyzers.UnitTests.csproj b/src/Analyzers.UnitTests/Microsoft.Build.Analyzers.UnitTests.csproj new file mode 100644 index 00000000000..dab550407fd --- /dev/null +++ b/src/Analyzers.UnitTests/Microsoft.Build.Analyzers.UnitTests.csproj @@ -0,0 +1,94 @@ + + + + + + + $(RuntimeOutputTargetFrameworks) + $(RuntimeOutputPlatformTarget) + false + True + Microsoft.Build.Analyzers.UnitTests + Microsoft.Build.Analyzers.UnitTests + + + + + + + + + + + + + + + + + + + + + + + Shared\TestEnvironment.cs + + + + Shared\FileUtilities.cs + + + Shared\TempFileUtilities.cs + + + Shared\ErrorUtilities.cs + + + Shared\EscapingUtilities.cs + + + Shared\BuildEnvironmentHelper.cs + + + Shared\ProcessExtensions.cs + + + Shared\ResourceUtilities.cs + + + Shared\ExceptionHandling.cs + + + Shared\FileUtilitiesRegex.cs + + + Shared\AssemblyResources.cs + + + Shared\RunnerUtilities.cs + + + Shared\EnvironmentProvider.cs + + + + + + App.config + Designer + + + PreserveNewest + + + + + + + + <_Parameter1>$(ArtifactsBinDir) + <_Parameter2>$(BootstrapBinaryDestination) + + + diff --git a/src/Framework/Properties/AssemblyInfo.cs b/src/Framework/Properties/AssemblyInfo.cs index 7de94ca1917..dfe95d4db15 100644 --- a/src/Framework/Properties/AssemblyInfo.cs +++ b/src/Framework/Properties/AssemblyInfo.cs @@ -46,6 +46,7 @@ [assembly: InternalsVisibleTo("Microsoft.Build.Conversion.Core, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] [assembly: InternalsVisibleTo("Microsoft.Build.Engine.UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010015c01ae1f50e8cc09ba9eac9147cf8fd9fce2cfe9f8dce4f7301c4132ca9fb50ce8cbf1df4dc18dd4d210e4345c744ecb3365ed327efdbc52603faa5e21daa11234c8c4a73e51f03bf192544581ebe107adee3a34928e39d04e524a9ce729d5090bfd7dad9d10c722c0def9ccc08ff0a03790e48bcd1f9b6c476063e1966a1c4")] +[assembly: InternalsVisibleTo("Microsoft.Build.Analyzers.UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010015c01ae1f50e8cc09ba9eac9147cf8fd9fce2cfe9f8dce4f7301c4132ca9fb50ce8cbf1df4dc18dd4d210e4345c744ecb3365ed327efdbc52603faa5e21daa11234c8c4a73e51f03bf192544581ebe107adee3a34928e39d04e524a9ce729d5090bfd7dad9d10c722c0def9ccc08ff0a03790e48bcd1f9b6c476063e1966a1c4")] // Ideally we wouldn't need to IVT to OM.UnitTests, which is supposed to test // only the public surface area of Microsoft.Build. However, there's a bunch // of shared code in Framework that's used there, and we can still avoid IVT diff --git a/src/UnitTests.Shared/RunnerUtilities.cs b/src/UnitTests.Shared/RunnerUtilities.cs index f836a7be6bd..3eb1026dfd2 100644 --- a/src/UnitTests.Shared/RunnerUtilities.cs +++ b/src/UnitTests.Shared/RunnerUtilities.cs @@ -33,24 +33,6 @@ public static string ExecMSBuild(string msbuildParameters, out bool successfulEx return ExecMSBuild(PathToCurrentlyRunningMsBuildExe, msbuildParameters, out successfulExit, outputHelper: outputHelper); } - /// - /// Invoke the currently running msbuild and return the stdout, stderr, and process exit status. - /// This method may invoke msbuild via other runtimes. - /// - public static string ExecBootstrapedMSBuild(string msbuildParameters, out bool successfulExit, bool shellExecute = false, ITestOutputHelper outputHelper = null) - { - // TODO: use proper way of passing the bootsrtrap location: https://github.com/dotnet/msbuild/issues/9729 - string basePath = PathToCurrentlyRunningMsBuildExe.Substring(0, PathToCurrentlyRunningMsBuildExe.IndexOf(@"artifacts\bin", StringComparison.InvariantCultureIgnoreCase)); -#if NET - string pathToExecutable = EnvironmentProvider.GetDotnetExePath(); - msbuildParameters = Path.Combine(basePath, @"artifacts\bin\bootstrap\net8.0\MSBuild\msbuild.dll") + " " + msbuildParameters; -#else - string pathToExecutable = - Path.Combine(basePath, @"artifacts\bin\bootstrap\net472\MSBuild\Current\Bin\amd64\msbuild.exe"); -#endif - return RunProcessAndGetOutput(pathToExecutable, msbuildParameters, out successfulExit, shellExecute, outputHelper); - } - /// /// Invoke msbuild.exe with the given parameters and return the stdout, stderr, and process exit status. /// This method may invoke msbuild via other runtimes.