diff --git a/src/Microsoft.VisualStudio.SlnGen.UnitTests/SlnFileTests.cs b/src/Microsoft.VisualStudio.SlnGen.UnitTests/SlnFileTests.cs index 6618466..fb96d9e 100644 --- a/src/Microsoft.VisualStudio.SlnGen.UnitTests/SlnFileTests.cs +++ b/src/Microsoft.VisualStudio.SlnGen.UnitTests/SlnFileTests.cs @@ -490,6 +490,68 @@ public void PathsWorkForAllDirectorySeparatorChars() actualSolutionText.ShouldBe(solutionText, StringCompareShould.IgnoreLineEndings); } + [Fact] + public void ProjectsNotBuildable() + { + const string solutionText = @"Microsoft Visual Studio Solution File, Format Version 12.00 +Project(""{9A19103F-16F7-4668-BE54-9A1E7A4F7556}"") = ""ProjectA"", ""ProjectA\ProjectA.csproj"", ""{E859E866-96F9-474E-A1EA-6539385AD236}"" +EndProject +Project(""{9A19103F-16F7-4668-BE54-9A1E7A4F7556}"") = ""ProjectB"", ""ProjectB\ProjectB.csproj"", ""{893607F9-C204-4CB2-8BF2-1F71B4198CD2}"" +EndProject +Project(""{9A19103F-16F7-4668-BE54-9A1E7A4F7556}"") = ""ProjectC"", ""ProjectC\ProjectC.csproj"", ""{081A3445-4E74-4AE9-95B6-FF564FE70CA3}"" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E859E866-96F9-474E-A1EA-6539385AD236}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E859E866-96F9-474E-A1EA-6539385AD236}.Release|Any CPU.ActiveCfg = Release|Any CPU + {893607F9-C204-4CB2-8BF2-1F71B4198CD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {893607F9-C204-4CB2-8BF2-1F71B4198CD2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {081A3445-4E74-4AE9-95B6-FF564FE70CA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {081A3445-4E74-4AE9-95B6-FF564FE70CA3}.Release|Any CPU.ActiveCfg = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {AA784BCF-D76D-4DD7-91D2-79E6A14A4DE2} + EndGlobalSection +EndGlobal +"; + + string solutionFileFullPath = GetTempFileName(".sln"); + + File.WriteAllText(solutionFileFullPath, solutionText); + + ProgramArguments programArguments = new ProgramArguments + { + LaunchVisualStudio = new[] { bool.FalseString }, + SolutionFileFullPath = new[] { solutionFileFullPath }, + Property = new[] { $"{MSBuildPropertyNames.SlnGenIsBuildable}={bool.FalseString};" }, + }; + + Project[] projects = + { + ProjectCreator.Templates.SdkCsproj(path: GetTempProjectFile("ProjectA")) + .Save(), + ProjectCreator.Templates.SdkCsproj(path: GetTempProjectFile("ProjectB")) + .Save(), + ProjectCreator.Templates.SdkCsproj(path: GetTempProjectFile("ProjectC")) + .Save(), + }; + + TestLogger testLogger = new TestLogger(); + + (string _, int customProjectTypeGuidCount, int solutionItemCount, Guid solutionGuid) = SlnFile.GenerateSolutionFile(programArguments, projects, testLogger); + + string actualSolutionText = File.ReadAllText(solutionFileFullPath); + + actualSolutionText.ShouldBe(solutionText, StringCompareShould.IgnoreLineEndings); + } + [Fact] public void TestSlnGenProjectNamePropertyForSolutionName() { diff --git a/src/Microsoft.VisualStudio.SlnGen.UnitTests/SlnProjectTests.cs b/src/Microsoft.VisualStudio.SlnGen.UnitTests/SlnProjectTests.cs index 277bd77..1a11a60 100644 --- a/src/Microsoft.VisualStudio.SlnGen.UnitTests/SlnProjectTests.cs +++ b/src/Microsoft.VisualStudio.SlnGen.UnitTests/SlnProjectTests.cs @@ -75,6 +75,16 @@ public void GetProjectGuidSdkProject() Guid.TryParse(actualProject.ProjectGuid.ToSolutionString(), out _).ShouldBeTrue(); } + [Theory] + [InlineData(true)] + [InlineData(false)] + public void GetIsBuildable(bool isBuildable) + { + SlnProject actualProject = CreateAndValidateProject(isBuildable: isBuildable); + + actualProject.IsBuildable.ShouldBe(isBuildable); + } + [Theory] [InlineData("")] [InlineData(ProjectFileExtensions.CSharp)] @@ -394,7 +404,7 @@ private static void ValidateParseCustomProjectTypeGuids(Project project, string actualProjectTypeGuid.Value.ShouldBe(expectedProjectTypeGuid); } - private SlnProject CreateAndValidateProject(bool isMainProject = false, string expectedGuid = null, string extension = ProjectFileExtensions.CSharp, IDictionary globalProperties = null, string isDeployable = null) + private SlnProject CreateAndValidateProject(bool isMainProject = false, string expectedGuid = null, string extension = ProjectFileExtensions.CSharp, IDictionary globalProperties = null, string isDeployable = null, bool isBuildable = true) { if (!isDeployable.IsNullOrWhiteSpace()) { @@ -405,7 +415,7 @@ private SlnProject CreateAndValidateProject(bool isMainProject = false, string e Project expectedProject = CreateProject(expectedGuid, extension, globalProperties); - SlnProject actualProject = SlnProject.FromProject(expectedProject, new Dictionary(), isMainProject); + SlnProject actualProject = SlnProject.FromProject(expectedProject, new Dictionary(), isMainProject, isBuildable); actualProject.FullPath.ShouldBe(expectedProject.FullPath); diff --git a/src/Microsoft.VisualStudio.SlnGen/MSBuildPropertyNames.cs b/src/Microsoft.VisualStudio.SlnGen/MSBuildPropertyNames.cs index fc2c448..ed0fca6 100644 --- a/src/Microsoft.VisualStudio.SlnGen/MSBuildPropertyNames.cs +++ b/src/Microsoft.VisualStudio.SlnGen/MSBuildPropertyNames.cs @@ -119,5 +119,10 @@ public static class MSBuildPropertyNames /// Represents the UsingMicrosoftNETSdk property. /// public const string UsingMicrosoftNETSdk = nameof(UsingMicrosoftNETSdk); + + /// + /// Represents the SlnGenIsBuildable property. + /// + public const string SlnGenIsBuildable = nameof(SlnGenIsBuildable); } } \ No newline at end of file diff --git a/src/Microsoft.VisualStudio.SlnGen/SlnFile.cs b/src/Microsoft.VisualStudio.SlnGen/SlnFile.cs index 2464d92..cb3fe98 100644 --- a/src/Microsoft.VisualStudio.SlnGen/SlnFile.cs +++ b/src/Microsoft.VisualStudio.SlnGen/SlnFile.cs @@ -208,7 +208,13 @@ public static (string solutionFileFullPath, int customProjectTypeGuidCount, int arguments.LoadProjectsInVisualStudio = new[] { bool.TrueString }; } - solution.AddProjects(projectList, customProjectTypeGuids, arguments.IgnoreMainProject ? null : firstProject.FullPath); + bool isBuildable = true; + if (arguments.GetGlobalProperties().TryGetValue(MSBuildPropertyNames.SlnGenIsBuildable, out string isBuildableString)) + { + isBuildable = bool.TrueString.Equals(isBuildableString, StringComparison.OrdinalIgnoreCase); + } + + solution.AddProjects(projectList, customProjectTypeGuids, arguments.IgnoreMainProject ? null : firstProject.FullPath, isBuildable); solution.AddSolutionItems(solutionItems); @@ -333,12 +339,13 @@ public void AddProjects(IEnumerable projects) /// An of projects to add. /// An containing any custom project type GUIDs to use. /// Optional full path to the main project. - public void AddProjects(IEnumerable projects, IReadOnlyDictionary customProjectTypeGuids, string mainProjectFullPath = null) + /// Indicates whether the projects are buildable. + public void AddProjects(IEnumerable projects, IReadOnlyDictionary customProjectTypeGuids, string mainProjectFullPath = null, bool isBuildable = true) { _projects.AddRange( projects .Distinct(new EqualityComparer((x, y) => string.Equals(x.FullPath, y.FullPath, StringComparison.OrdinalIgnoreCase), i => i.FullPath.GetHashCode())) - .Select(i => SlnProject.FromProject(i, customProjectTypeGuids, string.Equals(i.FullPath, mainProjectFullPath, StringComparison.OrdinalIgnoreCase))) + .Select(i => SlnProject.FromProject(i, customProjectTypeGuids, string.Equals(i.FullPath, mainProjectFullPath, StringComparison.OrdinalIgnoreCase), isBuildable)) .Where(i => i != null)); } diff --git a/src/Microsoft.VisualStudio.SlnGen/SlnProject.cs b/src/Microsoft.VisualStudio.SlnGen/SlnProject.cs index ca49a28..b29675b 100644 --- a/src/Microsoft.VisualStudio.SlnGen/SlnProject.cs +++ b/src/Microsoft.VisualStudio.SlnGen/SlnProject.cs @@ -135,8 +135,9 @@ public sealed class SlnProject /// The from MSBuild to create a solution project for. /// containing custom project type GUIDs. /// Indicates whether this project is the main project in the solution. + /// Indicates whether this project is buildable. /// A for the specified MSBuild project. - public static SlnProject FromProject(Project project, IReadOnlyDictionary customProjectTypeGuids, bool isMainProject = false) + public static SlnProject FromProject(Project project, IReadOnlyDictionary customProjectTypeGuids, bool isMainProject = false, bool isBuildable = true) { if (project == null) { @@ -193,6 +194,7 @@ public static SlnProject FromProject(Project project, IReadOnlyDictionary(), SolutionFolder = project.GetPropertyValueOrDefault(MSBuildPropertyNames.SlnGenSolutionFolder, string.Empty), + IsBuildable = isBuildable, }; }