Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use MSbuild APIs to Retrieve Projects Properties #45724

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
e9c2a23
Use msbuild APIs to load projects
mariam-abdulla Jan 3, 2025
e7bcc8a
Add space
mariam-abdulla Jan 3, 2025
8d747c7
Fix formatting
mariam-abdulla Jan 6, 2025
2b02833
Add comments
mariam-abdulla Jan 6, 2025
f4cce4e
Update src/Cli/dotnet/commands/dotnet-test/TestingPlatformCommand.cs
mariam-abdulla Jan 6, 2025
f078060
Replace 0 and 1 with constants
mariam-abdulla Jan 6, 2025
4c9add2
Merge branch 'dev/mabdullah/use-msbuild-apis-to-retrieve-project-prop…
mariam-abdulla Jan 6, 2025
771c1f1
Return from InitializeTestApplications() if _areTestingPlatformApplic…
mariam-abdulla Jan 6, 2025
def3cb8
Update method name
mariam-abdulla Jan 6, 2025
3b75ca8
Use aggregator overload in ProcessProjectsInParallel()
mariam-abdulla Jan 6, 2025
8e3b723
Apply some comments
mariam-abdulla Jan 6, 2025
b7b79ef
Remove ?
mariam-abdulla Jan 7, 2025
5349e6c
Update GetSolutionFilePaths
mariam-abdulla Jan 7, 2025
cbc3389
Use Microsoft.VisualStudio.SolutionPersistence namespace to parse sol…
mariam-abdulla Jan 7, 2025
9284893
Add GetSlnFileFullPath and GetProjectFileFullPath methods in Extensio…
mariam-abdulla Jan 7, 2025
6b42f48
Refactor
mariam-abdulla Jan 7, 2025
51c7424
Update ParseSolution to use GetSerializerByMoniker
mariam-abdulla Jan 7, 2025
3855845
Merge branch 'main' into dev/mabdullah/use-msbuild-apis-to-retrieve-p…
mariam-abdulla Jan 8, 2025
082f260
Update src/Cli/dotnet/commands/dotnet-test/TestingPlatformCommand.cs
mariam-abdulla Jan 8, 2025
ae87351
Update src/Cli/dotnet/commands/dotnet-test/SolutionAndProjectUtility.cs
mariam-abdulla Jan 8, 2025
3e26cd3
Update src/Cli/dotnet/commands/dotnet-test/SolutionAndProjectUtility.cs
mariam-abdulla Jan 8, 2025
31593b0
Update src/Cli/dotnet/commands/dotnet-test/SolutionAndProjectUtility.cs
mariam-abdulla Jan 8, 2025
f781164
Update src/Cli/dotnet/commands/dotnet-test/SolutionAndProjectUtility.cs
mariam-abdulla Jan 8, 2025
7e359d1
Merge branch 'main' into dev/mabdullah/use-msbuild-apis-to-retrieve-p…
mariam-abdulla Jan 8, 2025
3c3d56b
Update src/Cli/dotnet/commands/dotnet-test/SolutionAndProjectUtility.cs
mariam-abdulla Jan 8, 2025
55d247d
Apply comments
mariam-abdulla Jan 8, 2025
d3b11c5
merge
mariam-abdulla Jan 8, 2025
41323d4
Update src/Cli/dotnet/commands/dotnet-test/SolutionAndProjectUtility.cs
mariam-abdulla Jan 8, 2025
a774524
Use Lock
mariam-abdulla Jan 8, 2025
9d17be2
Merge branch 'dev/mabdullah/use-msbuild-apis-to-retrieve-project-prop…
mariam-abdulla Jan 8, 2025
3f66a69
Update -bl logic
mariam-abdulla Jan 8, 2025
97b5ae9
Merge branch 'main' into dev/mabdullah/use-msbuild-apis-to-retrieve-p…
mariam-abdulla Jan 8, 2025
4f2b769
Remove unused var
mariam-abdulla Jan 8, 2025
6504a67
Merge branch 'dev/mabdullah/use-msbuild-apis-to-retrieve-project-prop…
mariam-abdulla Jan 8, 2025
ddb5bb4
Merge branch 'main' into dev/mabdullah/use-msbuild-apis-to-retrieve-p…
mariam-abdulla Jan 9, 2025
5e26d3d
Merge branch 'main' into dev/mabdullah/use-msbuild-apis-to-retrieve-p…
mariam-abdulla Jan 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Use Microsoft.VisualStudio.SolutionPersistence namespace to parse sol…
…ution files
  • Loading branch information
mariam-abdulla committed Jan 7, 2025
commit cbc3389c48dde8c073290e3f5002bf26d585d7f3
15 changes: 8 additions & 7 deletions src/Cli/dotnet/commands/dotnet-test/MSBuildHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ internal sealed class MSBuildHandler : IDisposable
private bool _areTestingPlatformApplications = true;

private const string BinLogFileName = "msbuild.binlog";
private const string Separator = ";";
private static readonly object s_buildLock = new();
mariam-abdulla marked this conversation as resolved.
Show resolved Hide resolved

public MSBuildHandler(List<string> args, TestApplicationActionQueue actionQueue, int degreeOfParallelism)
Expand All @@ -28,7 +29,7 @@ public MSBuildHandler(List<string> args, TestApplicationActionQueue actionQueue,
_degreeOfParallelism = degreeOfParallelism;
}

public int RunWithMSBuild(bool allowBinLog)
public async Task<int> RunWithMSBuild(bool allowBinLog)
{
bool solutionOrProjectFileFound = SolutionAndProjectUtility.TryGetSolutionOrProjectFilePath(Directory.GetCurrentDirectory(), out string filePath, out bool isSolution);

Expand All @@ -37,16 +38,16 @@ public int RunWithMSBuild(bool allowBinLog)
return ExitCodes.GenericFailure;
}

(IEnumerable<Module> modules, bool restored) = GetProjectsProperties(filePath, isSolution, allowBinLog);
(IEnumerable<Module> modules, bool restored) = await GetProjectsProperties(filePath, isSolution, allowBinLog);

InitializeTestApplications(modules);

return restored ? ExitCodes.Success : ExitCodes.GenericFailure;
}

public int RunWithMSBuild(string filePath, bool allowBinLog)
public async Task<int> RunWithMSBuild(string filePath, bool allowBinLog)
{
(IEnumerable<Module> modules, bool restored) = GetProjectsProperties(filePath, false, allowBinLog);
(IEnumerable<Module> modules, bool restored) = await GetProjectsProperties(filePath, false, allowBinLog);

InitializeTestApplications(modules);

Expand Down Expand Up @@ -84,14 +85,14 @@ public bool EnqueueTestApplications()
return true;
}

private (IEnumerable<Module>, bool Restored) GetProjectsProperties(string solutionOrProjectFilePath, bool isSolution, bool allowBinLog)
private async Task<(IEnumerable<Module>, bool Restored)> GetProjectsProperties(string solutionOrProjectFilePath, bool isSolution, bool allowBinLog)
{
var allProjects = new ConcurrentBag<Module>();
bool restored = true;

if (isSolution)
{
var projects = SolutionAndProjectUtility.GetProjectsFromSolutionFile(solutionOrProjectFilePath);
var projects = await SolutionAndProjectUtility.ParseSolution(solutionOrProjectFilePath);
ProcessProjectsInParallel(projects, allowBinLog, allProjects, ref restored);
}
else
Expand Down Expand Up @@ -174,7 +175,7 @@ private static IEnumerable<Module> ExtractModulesFromProject(Project project)
}
else
{
var frameworks = targetFrameworks.Split(';', StringSplitOptions.RemoveEmptyEntries);
var frameworks = targetFrameworks.Split(Separator, StringSplitOptions.RemoveEmptyEntries);
foreach (var framework in frameworks)
{
project.SetProperty(ProjectProperties.TargetFramework, framework);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.Build.Construction;
using Microsoft.DotNet.Tools.Test;
using Microsoft.VisualStudio.SolutionPersistence.Model;
using Microsoft.VisualStudio.SolutionPersistence.Serializer;

namespace Microsoft.DotNet.Cli
{
Expand Down Expand Up @@ -45,17 +46,47 @@ public static bool TryGetSolutionOrProjectFilePath(string directory, out string
return false;
}

public static IEnumerable<string> GetProjectsFromSolutionFile(string solutionFilePath)
public static async Task<IEnumerable<string>> ParseSolution(string solutionFilePath)
{
var solutionFile = SolutionFile.Parse(solutionFilePath);
return solutionFile.ProjectsInOrder.Select(project => project.AbsolutePath);
if (string.IsNullOrEmpty(solutionFilePath))
{
VSTestTrace.SafeWriteTrace(() => $"Solution file path cannot be null or empty: {solutionFilePath}");
return [];
}

var projectsPaths = new List<string>();
SolutionModel solution = null;

try
{
using var stream = new FileStream(solutionFilePath, FileMode.Open, FileAccess.Read);
string extension = Path.GetExtension(solutionFilePath);

solution = extension.Equals(".sln", StringComparison.OrdinalIgnoreCase)
? await SolutionSerializers.SlnFileV12.OpenAsync(stream, CancellationToken.None)
: extension.Equals(".slnx", StringComparison.OrdinalIgnoreCase)
? await SolutionSerializers.SlnXml.OpenAsync(stream, CancellationToken.None)
: null;
mariam-abdulla marked this conversation as resolved.
Show resolved Hide resolved
}
catch (Exception ex)
{
VSTestTrace.SafeWriteTrace(() => $"Failed to parse solution file '{solutionFilePath}': {ex.Message}");
return [];
}

if (solution is not null)
{
projectsPaths = [.. solution.SolutionProjects.Select(project => project.FilePath)];
}

return projectsPaths;
}

private static string[] GetSolutionFilePaths(string directory)
{
var solutionFiles = Directory.GetFiles(directory, "*.sln", SearchOption.TopDirectoryOnly)
.Concat(Directory.GetFiles(directory, "*.slnx", SearchOption.TopDirectoryOnly))
.ToArray();
string[] solutionFiles = [
..Directory.GetFiles(directory, "*.sln", SearchOption.TopDirectoryOnly),
..Directory.GetFiles(directory, "*.slnx", SearchOption.TopDirectoryOnly)];

return solutionFiles;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Cli/dotnet/commands/dotnet-test/TestCommandParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ private static CliCommand ConstructCommand()
private static CliCommand GetTestingPlatformCliCommand()
{
var command = new TestingPlatformCommand("test");
command.SetAction((parseResult) => command.Run(parseResult));
command.SetAction(async (parseResult) => await command.Run(parseResult));
command.Options.Add(TestingPlatformOptions.MaxParallelTestModulesOption);
command.Options.Add(TestingPlatformOptions.AdditionalMSBuildParametersOption);
command.Options.Add(TestingPlatformOptions.TestModulesFilterOption);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ internal partial class TestingPlatformCommand

public IEnumerable<Action<HelpContext>> CustomHelpLayout()
{
yield return (context) =>
yield return async (context) =>
{
Console.WriteLine("Waiting for options and extensions...");

Run(context.ParseResult);
await Run(context.ParseResult);

if (_commandLineOptionNameToModuleNames.IsEmpty)
{
Expand Down
21 changes: 11 additions & 10 deletions src/Cli/dotnet/commands/dotnet-test/TestingPlatformCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public TestingPlatformCommand(string name, string description = null) : base(nam
TreatUnmatchedTokensAsErrors = false;
}

public int Run(ParseResult parseResult)
public async Task<int> Run(ParseResult parseResult)
{
bool hasFailed = false;
try
Expand Down Expand Up @@ -90,7 +90,8 @@ public int Run(ParseResult parseResult)
else
{
bool allowBinLog = IsBinLogEnabled(_args);
if (!RunMSBuild(parseResult, allowBinLog))

if (!await RunMSBuild(parseResult, allowBinLog))
{
return ExitCodes.GenericFailure;
}
Expand All @@ -116,32 +117,32 @@ public int Run(ParseResult parseResult)
return hasFailed ? ExitCodes.GenericFailure : ExitCodes.Success;
}

private bool RunMSBuild(ParseResult parseResult, bool allowBinLog)
private async Task<bool> RunMSBuild(ParseResult parseResult, bool allowBinLog)
{
int msbuildResult;
int msbuildExitCode;

if (parseResult.HasOption(TestingPlatformOptions.ProjectOption))
{
string filePath = parseResult.GetValue(TestingPlatformOptions.ProjectOption);

if (!File.Exists(filePath))
{
VSTestTrace.SafeWriteTrace(() => LocalizableStrings.CmdNonExistentProjectFilePathDescription);
VSTestTrace.SafeWriteTrace(() => string.Format(LocalizableStrings.CmdNonExistentProjectFilePathDescription, filePath));
return false;
}

msbuildResult = _msBuildConnectionHandler.RunWithMSBuild(filePath, allowBinLog);
msbuildExitCode = await _msBuildConnectionHandler.RunWithMSBuild(filePath, allowBinLog);
}
else
{
// If no filter was provided neither the project using --project,
// MSBuild will get the test project paths in the current directory
msbuildResult = _msBuildConnectionHandler.RunWithMSBuild(allowBinLog);
msbuildExitCode = await _msBuildConnectionHandler.RunWithMSBuild(allowBinLog);
}

if (msbuildResult != 0)
if (msbuildExitCode != ExitCodes.Success)
{
VSTestTrace.SafeWriteTrace(() => LocalizableStrings.CmdMSBuildProjectsPropertiesErrorMessage);
VSTestTrace.SafeWriteTrace(() => string.Format(LocalizableStrings.CmdMSBuildProjectsPropertiesErrorMessage, msbuildExitCode));
return false;
}

Expand Down Expand Up @@ -272,7 +273,7 @@ private void OnTestProcessExited(object sender, TestProcessExitEventArgs args)
return;
}

if (args.ExitCode != 0)
if (args.ExitCode != ExitCodes.Success)
{
VSTestTrace.SafeWriteTrace(() => $"Test Process exited with non-zero exit code: {args.ExitCode}");
}
Expand Down
Loading