8000 sln-add: --include-references when adding a project (#48815) · dotnet/sdk@509db15 · GitHub
[go: up one dir, main page]

Skip to content

Commit 509db15

Browse files
authored
sln-add: --include-references when adding a project (#48815)
1 parent 07620ea commit 509db15

24 files changed

+179
-4
lines changed

src/Cli/dotnet/Commands/CliCommandStrings.resx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2483,4 +2483,7 @@ To display a value, specify the corresponding command-line option without provid
24832483
<data name="ZeroTestsRan" xml:space="preserve">
24842484
<value>Zero tests ran</value>
24852485
</data>
2486-
</root>
2486+
<data name="SolutionAddReferencedProjectsOptionDescription" xml:space="preserve">
2487+
<value>Recursively add projects' ReferencedProjects to solution</value>
2488+
</data>
2489+
</root>

src/Cli/dotnet/Commands/Solution/Add/SolutionAddCommand.cs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ internal class SolutionAddCommand : CommandBase
2222
private readonly IReadOnlyCollection<string> _projects;
2323
private readonly string? _solutionFolderPath;
2424
private string _solutionFileFullPath = string.Empty;
25+
private bool _includeReferences;
2526

2627
private static string GetSolutionFolderPathWithForwardSlashes(string path)
2728
{
@@ -43,6 +44,7 @@ public SolutionAddCommand(ParseResult parseResult) : base(parseResult)
4344
_projects = (IReadOnlyCollection<string>)(parseResult.GetValue(SolutionAddCommandParser.ProjectPathArgument) ?? []);
4445
_inRoot = parseResult.GetValue(SolutionAddCommandParser.InRootOption);
4546
_solutionFolderPath = parseResult.GetValue(SolutionAddCommandParser.SolutionFolderOption);
47+
_includeReferences = parseResult.GetValue(SolutionAddCommandParser.IncludeReferencesOption);
4648
SolutionArgumentValidator.ParseAndValidateArguments(_fileOrDirectory, _projects, SolutionArgumentValidator.CommandType.Add, _inRoot, _solutionFolderPath);
4749
_solutionFileFullPath = SlnFileFactory.GetSolutionFileFullPath(_fileOrDirectory);
4850
}
@@ -138,7 +140,7 @@ private async Task AddProjectsToSolutionAsync(IEnumerable<string> projectPaths,
138140
await serializer.SaveAsync(_solutionFileFullPath, solution, cancellationToken);
139141
}
140142

141-
private void AddProject(SolutionModel solution, string fullProjectPath, ISolutionSerializer serializer = null)
143+
private void AddProject(SolutionModel solution, string fullProjectPath, ISolutionSerializer serializer = null, bool showMessageOnDuplicate = true)
142144
{
143145
string solutionRelativeProjectPath = Path.GetRelativePath(Path.GetDirectoryName(_solutionFileFullPath), fullProjectPath);
144146

@@ -175,7 +177,10 @@ private void AddProject(SolutionModel solution, string fullProjectPath, ISolutio
175177
}
176178
catch (SolutionArgumentException ex) when (ex.Type == SolutionErrorType.DuplicateProjectName || solution.FindProject(solutionRelativeProjectPath) is not null)
177179
{
178-
Reporter.Output.WriteLine(CliStrings.SolutionAlreadyContainsProject, _solutionFileFullPath, solutionRelativeProjectPath);
180+
if (showMessageOnDuplicate)
181+
{
182+
Reporter.Output.WriteLine(CliStrings.SolutionAlreadyContainsProject, _solutionFileFullPath, solutionRelativeProjectPath);
183+
}
179184
return;
180185
}
181186

@@ -205,5 +210,17 @@ private void AddProject(SolutionModel solution, string fullProjectPath, ISolutio
205210
}
206211

207212
Reporter.Output.WriteLine(CliStrings.ProjectAddedToTheSolution, solutionRelativeProjectPath);
213+
214+
// Get referencedprojects from the project instance
215+
var referencedProjectsFullPaths = projectInstance.GetItems("ProjectReference")
216+
.Select(item => Path.GetFullPath(item.EvaluatedInclude, Path.GetDirectoryName(fullProjectPath)));
217+
218+
if (_includeReferences)
219+
{
220+
foreach (var referencedProjectFullPath in referencedProjectsFullPaths)
221+
{
222+
AddProject(solution, referencedProjectFullPath, serializer, showMessageOnDuplicate: false);
223+
}
224+
}
208225
}
209226
}

src/Cli/dotnet/Commands/Solution/Add/SolutionAddCommandParser.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#nullable disable
55

66
using System.CommandLine;
7+
using System.CommandLine.Parsing;
78

89
namespace Microsoft.DotNet.Cli.Commands.Solution.Add;
910

@@ -26,6 +27,12 @@ public static class SolutionAddCommandParser
2627
Description = CliCommandStrings.AddProjectSolutionFolderArgumentDescription
2728
};
2829

30+
public static readonly Option<bool> IncludeReferencesOption = new("--include-references")
31+
{
32+
Description = CliCommandStrings.SolutionAddReferencedProjectsOptionDescription,
33+
DefaultValueFactory = (_) => true,
34+
};
35+
2936
private static readonly Command Command = ConstructCommand();
3037

3138
public static Command GetCommand()
@@ -40,6 +47,7 @@ private static Command ConstructCommand()
4047
command.Arguments.Add(ProjectPathArgument);
4148
command.Options.Add(InRootOption);
4249
command.Options.Add(SolutionFolderOption);
50+
command.Options.Add(IncludeReferencesOption);
4351

4452
command.SetAction((parseResult) => new SolutionAddCommand(parseResult).Execute());
4553

src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net10.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
<ItemGroup>
10+
<ProjectReference Include="..\B\B.csproj" />
11+
</ItemGroup>
12+
</Project>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.0.31903.59
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Global
7+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
8+
Debug|Any CPU = Debug|Any CPU
9+
Release|Any CPU = Release|Any CPU
10+
EndGlobalSection
11+
GlobalSection(SolutionProperties) = preSolution
12+
HideSolutionNode = FALSE
13+
EndGlobalSection
14+
EndGlobal
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<Solution>
2+
</Solution>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net10.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
10+
</Project>

test/dotnet.Tests/CommandTests/Solution/Add/GivenDotnetSlnAdd.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using Microsoft.VisualStudio.SolutionPersistence;
99
using Microsoft.VisualStudio.SolutionPersistence.Model;
1010
using Microsoft.DotNet.Cli.Commands;
11+
using System.Threading.Tasks;
1112

1213
namespace Microsoft.DotNet.Cli.Sln.Add.Tests
1314
{
@@ -36,6 +37,7 @@ dotnet solution <SLN_FILE> add [<PROJECT_PATH>...] [options]
3637
Options:
3738
--in-root Place project in root of the solution, rather than creating a solution folder.
3839
-s, --solution-folder <solution-folder> The destination solution folder path to add the projects to.
40+
--include-references Recursively add projects' ReferencedProjects to solution [default: True]
3941
-?, -h, --help Show command line help";
4042

4143
public GivenDotnetSlnAdd(ITestOutputHelper log) : base(log)
@@ -1154,6 +1156,40 @@ public async Task WhenAddingProjectOutsideDirectoryItShouldNotAddSolutionFolders
11541156
solution.SolutionFolders.Count.Should().Be(0);
11551157
}
11561158

1159+
[Theory]
1160+
[InlineData("sln", ".sln", "--include-references=true")]
1161+
[InlineData("solution", ".sln", "--include-references=true")]
1162+
[InlineData("sln", ".slnx", "--include-references=true")]
1163+
[InlineData("solution", ".slnx", "--include-references=true")]
1164+
[InlineData("sln", ".sln", "--include-references=false")]
1165+
[InlineData("solution", ".sln", "--include-references=false")]
1166+
[InlineData("sln", ".slnx", "--include-references=false")]
1167+
[InlineData("solution", ".slnx", "--include-references=false")]
1168+
public async Task WhenSolutionIsPassedAProjectWithReferenceItAddsOtherProjectUnlessSpecified(string solutionCommand, string solutionExtension, string option)
1169+
{
1170+
var projectDirectory = _testAssetsManager
1171+
.CopyTestAsset("SlnFileWithReferencedProjects", identifier: $"GivenDotnetSlnAdd-{solutionCommand}")
1172+
.WithSource()
1173+
.Path;
1174+
var projectToAdd = Path.Combine("A", "A.csproj");
1175+
var cmd = new DotnetCommand(Log)
1176+
.WithWorkingDirectory(Path.Join(projectDirectory))
1177+
.Execute(solutionCommand, $"App{solutionExtension}", "add", projectToAdd, option);
1178+
cmd.Should().Pass();
1179+
// Should have two projects
1180+
ISolutionSerializer serializer = SolutionSerializers.GetSerializerByMoniker(Path.Join(projectDirectory, $"App{solutionExtension}"));
1181+
SolutionModel solution = await serializer.OpenAsync(Path.Join(projectDirectory, $"App{solutionExtension}"), CancellationToken.None);
1182+
1183+
if (option.Equals("--include-references=false")) // Option is true by default
1184+
{
1185+
solution.SolutionProjects.Count.Should().Be(1);
1186+
}
1187+
else
1188+
{
1189+
solution.SolutionProjects.Count.Should().Be(2);
1190+
}
1191+
}
1192+
11571193
private string GetExpectedSlnContents(
11581194
string slnPath,
11591195
string slnTemplateName,
@@ -1237,6 +1273,8 @@ public void WhenSolutionIsPassedAsProjectWithSolutionFolderItPrintsSuggestionAnd
12371273
{
12381274
VerifySuggestionAndUsage(solutionCommand, "--solution-folder", solutionExtension);
12391275
}
1276+
1277+
12401278
private void VerifySuggestionAndUsage(string solutionCommand, string arguments, string solutionExtension)
12411279
{
12421280
var projectDirectory = _testAssetsManager

test/dotnet.Tests/CompletionTests/snapshots/bash/DotnetCliSnapshotTests.VerifyCompletions.verified.sh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1421,7 +1421,7 @@ _testhost_solution_add() {
14211421
prev="${COMP_WORDS[COMP_CWORD-1]}"
14221422
COMPREPLY=()
14231423

1424-
opts="--in-root --solution-folder --help"
1424+
opts="--in-root --solution-folder --include-references --help"
14251425

14261426
if [[ $COMP_CWORD == "$1" ]]; then
14271427
COMPREPLY=( $(compgen -W "$opts" -- "$cur") )
@@ -1433,6 +1433,10 @@ _testhost_solution_add() {
14331433
COMPREPLY=( $(compgen -W "False True" -- "$cur") )
14341434
return
14351435
;;
1436+
--include-references)
1437+
COMPREPLY=( $(compgen -W "False True" -- "$cur") )
1438+
return
1439+
;;
14361440
esac
14371441

14381442
COMPREPLY=( $(compgen -W "$opts" -- "$cur") )

test/dotnet.Tests/CompletionTests/snapshots/pwsh/DotnetCliSnapshotTests.VerifyCompletions.verified.ps1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,7 @@ Register-ArgumentCompleter -Native -CommandName 'testhost' -ScriptBlock {
840840
[CompletionResult]::new('--in-root', '--in-root', [CompletionResultType]::ParameterName, "Place project in root of the solution, rather than creating a solution folder.")
841841
[CompletionResult]::new('--solution-folder', '--solution-folder', [CompletionResultType]::ParameterName, "The destination solution folder path to add the projects to.")
842842
[CompletionResult]::new('--solution-folder', '-s', [CompletionResultType]::ParameterName, "The destination solution folder path to add the projects to.")
843+
[CompletionResult]::new('--include-references', '--include-references', [CompletionResultType]::ParameterName, "Recursively add projects`' ReferencedProjects to solution")
843844
[CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, "Show command line help.")
844845
[CompletionResult]::new('--help', '-h', [CompletionResultType]::ParameterName, "Show command line help.")
845846
)

0 commit comments

Comments
 (0)
0