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

sln-add: Support for slnx #44570

Open
wants to merge 55 commits into
base: main
Choose a base branch
from
Open

sln-add: Support for slnx #44570

wants to merge 55 commits into from

Conversation

edvilme
Copy link
Member

@edvilme edvilme commented Oct 31, 2024

Contributes to #40913

The dotnet CLI should support the new slnx format for building and in the existing solution management commands. It should also help interested users migrate to the new format.

This adds dotnet sln add support for .slnx files

@edvilme edvilme force-pushed the edvilme-slnx-add branch 2 times, most recently from d397257 to b6aa066 Compare November 5, 2024 20:55
@kasperk81
Copy link
Contributor

@edvilme checkout the complete feedback. using solution.FindProject makes the regex usage irrelevant

@kasperk81
Copy link
Contributor

that will hopefully fix errors like
System.Exception : Test dir /private/tmp/helix/working/BD4A0AC6/w/9AEF084D/e/testExecutionDirectory/WhenInvalidSo---41AFE22E_2 already exists

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, const strings for expected sln results were moved to a folder under TestAssets, with their .slnx counterparts generated by dotnet sln migrate.
Additional test cases were created for sln.
SlnFile was removed from these tests as well

@kasperk81
Copy link
Contributor

kasperk81 commented Nov 26, 2024

the identifier doesn't help because testmanager's GetTestDestinationDirectoryPath shortens the directory name to 24 characters and we end up having the same errors.

short-term solution is #45130 which goes beyond _2 in the ci.

long-term solution is to make GetTestDestinationDirectoryPath stateless and use Path.GetTempFileName without any hashing or ci specific complexity; right now there are tests like GivenThatWeWantToVerifyNuGetReferenceCompat.Nuget_reference_compat which end up calling GetTestDestinationDirectoryPath multiple times during a single test run and expects names to be deterministic. it is fragile as is because in ci case, it also checks if the directory exists and start using _1 and _2 suffix so the second time it will be called it will get one of those suffixes. so it's at the verge of breakage as we can see in this pr. making sure that name is generated no more than once per test and using that name will make it stateless.

@edvilme
Copy link
Member Author

edvilme commented Nov 26, 2024

the identifier doesn't help because testmanager's GetTestDestinationDirectoryPath shortens the directory name to 24 characters and we end up having the same errors.

Yes, it pushed before I was able to see your pr, bit of a sync issue there... I like the idea on your PR as it allows us to have a greater variety of different names for different cases (of which there are many on this pr)

@kasperk81
Copy link
Contributor

getting closer! 👍

these tests are failing:

public void AddProjectToSolution_BasicInSolutionRoot()

public void AddProjectToSolution_WithOutputAbsolutePath()

public void AddProjectToSolution_WithOutputRelativePath()

Expected command to not output to stderr but it was not:  
File Name: /Users/runner/work/1/s/artifacts/bin/redist/Release/dotnet/dotnet  
Arguments: new TestAssets.PostActions.AddProjectToSolution.Basic -n MyProject -o output --debug:custom-hive /Users/runner/work/1/s/artifacts/tmp/Release/dotnet-new.IntegrationTests/AddProjectToSolution_WithOutputRelativePath/Home/20241126201252329  
Exit Code: 0  
StdOut:  
The template "TestAssets.PostActions.AddProjectToSolution.Basic" was created successfully.  

Processing post-creation actions...  
Adding  
    project(s): /Users/runner/work/1/s/artifacts/tmp/Release/dotnet-new.IntegrationTests/AddProjectToSolution_WithOutputRelativePath/20241126201252329/output/MyProject.csproj  
    to solution file: /Users/runner/work/1/s/artifacts/tmp/Release/dotnet-new.IntegrationTests/AddProjectToSolution_WithOutputRelativePath/20241126201252329/output/MySolution.sln  
    solution folder: src  
Successfully added project(s) to a solution file.  

StdErr:  
Invalid project /Users/runner/work/1/s/artifacts/tmp/Release/dotnet-new.IntegrationTests/AddProjectToSolution_WithOutputRelativePath/20241126201252329/output/MyProject.csproj. The project file could not be loaded. Could not find file '/Users/runner/work/1/s/artifacts/tmp/Release/dotnet-new.IntegrationTests/AddProjectToSolution_WithOutputRelativePath/20241126201252329/MyProject.csproj'.  /Users/runner/work/1/s/artifacts/tmp/Release/dotnet-new.IntegrationTests/AddProjectToSolution_WithOutputRelativePath/20241126201252329/MyProject.csproj.

test is adding 20241126201252329/output/MyProject.csproj to sln and expecting 20241126201252329/MyProject.csproj (without the /output part)

@edvilme
Copy link
Member Author

edvilme commented Nov 27, 2024

getting closer! 👍

these tests are failing:

Hii, thanks and thanks for your input. Yes, those tests are currently failing on several PRs and should be unrelated to the changes here. When they're fixed, I will update the branch :)

@kasperk81
Copy link
Contributor

those tests are currently failing on several PRs and should be unrelated to the changes here

can you point me to it?
pr:

git checkout edvilme-slnx-add
./build.sh
.dotnet/dotnet test test/dotnet-new.Tests --filter 'AddProjectToSolution_BasicInSolutionRoot|AddProjectToSolution_WithOutputAbsolutePath|AddProjectToSolution_WithOutputRelativePath' 

Test summary: total: 3, failed: 3, succeeded: 0, skipped: 0, duration: 5,1s

main:

git checkout main
./build.sh
.dotnet/dotnet test test/dotnet-new.Tests --filter 'AddProjectToSolution_BasicInSolutionRoot|AddProjectToSolution_WithOutputAbsolutePath|AddProjectToSolution_WithOutputRelativePath' 

Test summary: total: 3, failed: 0, succeeded: 3, skipped: 0, duration: 6,4s

with 5 retries back and forth, those three tests 100% of the times fail with your branch locally and pass with main

@edvilme
Copy link
Member Author

edvilme commented Nov 27, 2024

You're right. There were some other tests from templating failing, so I got them mixed up. The issue here is when adding projects from a different directory, e.g., dotnet sln subdirectory/App.sln add subdirectory/Project.csproj. I will look into that

Copy link
Contributor

@kasperk81 kasperk81 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm (one nit)

Directory.Packages.props Outdated Show resolved Hide resolved
Copy link
Member

@Forgind Forgind left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly just questions 🙂 Thanks for all your work to enable this!

PathUtility.EnsureAllPathsExist(arguments, CommonLocalizableStrings.CouldNotFindProjectOrDirectory, true);

var fullProjectPaths = _arguments.Select(p =>
try
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: \n before this

(Also just anywhere you have }, I prefer a \n before the next thing with few exceptions)

AddProjectsToSolutionAsync(solutionFileFullPath, fullProjectPaths, CancellationToken.None).Wait();
return 0;
}
catch (GracefulException)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other catch explicitly excludes this case, and this case just throws, so we can skip this block.


var currentDirString = $".{Path.DirectorySeparatorChar}";
if (projectFilePath.StartsWith(currentDirString))
ISolutionSerializer serializer = SlnCommandParser.GetSolutionSerializer(solutionFileFullPath);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a new runtime concept? I don't see it in the SDK currently or in this PR, and a quick bing (google) search didn't reveal anything interesting. If so, should we put this behind #ifdefs?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which part are you refering to here?

ISolutionSerializer serializer = SlnCommandParser.GetSolutionSerializer(solutionFileFullPath);
SolutionModel solution = await serializer.OpenAsync(solutionFileFullPath, cancellationToken);
// set UTF8 BOM encoding for .sln
if (serializer is ISolutionSerializer<SlnV12SerializerSettings> v12Serializer)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the significance of V12?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://github.com/microsoft/vs-solutionpersistence/tree/main/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/SlnV12

i think the "v12" format ensures compatibility with Visual Studio 2013 and later versions. previous versions of vs might not understand solution files created in this schema unless explicitly backported. It has enhanced support for modern project types, including new sdk-style projects and multi-targeting and better integration with msbuild, with the solution file acting as a meta-structure over the projects it includes.

{
if (_inRoot)
// Set default configurations and platforms for sln file
foreach (var platform in new[]{ "Any CPU", "x64", "x86" })
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought we supported ARM now? Not relevant here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yea platform can be arm/arm64 as well

<When Condition="$(RuntimeIdentifier.EndsWith('-arm64')) or $(RuntimeIdentifier.Contains('-arm64-'))">
(these are applicable to visual studio, msbuild and roslyn)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, platform can be arm64 too, however this was added as to not break existing changes. In one of the comments I suggest maybe making this a constant so we can modify it easily in the future (?)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a drop-in replacement for what dotnet sln add generates today. visual studio generates the similar file when you create a project with solution (it has no arm or arm64).

so far there is no issue showing that it has ever been a requirement from users but even if it is requirement it should be added as a new opt-in option on dotnet sln add command so user can decide if they want to add more platforms

foreach (var solutionPlatform in solution.Platforms)
{
var projectPlatform = projectInstancePlatforms.FirstOrDefault(
x => x.Replace(" ", string.Empty) == solutionPlatform.Replace(" ", string.Empty), projectInstancePlatforms.FirstOrDefault("Any CPU"));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: better name for 'x'?

}
foreach (var solutionPlatform in solution.Platforms)
{
var projectPlatform = projectInstancePlatforms.FirstOrDefault(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there are multiple, we only care about the first?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we currently have a test that checks if the first match is added

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Infrastructure untriaged Request triage from a team member
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants