Skip to content

Commit

Permalink
add slnx support (#130)
Browse files Browse the repository at this point in the history
  • Loading branch information
sensslen authored Feb 3, 2025
1 parent 6d91ecf commit 6606dcb
Show file tree
Hide file tree
Showing 23 changed files with 81 additions and 80 deletions.
30 changes: 4 additions & 26 deletions .github/workflows/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,9 @@ jobs:
matrix:
os: [ubuntu-latest, macos-latest]

framework: [net6.0, net8.0, net9.0]
framework: [net8.0, net9.0]

include:
- framework: net6.0
dotnetVersion: "6.0.x"

- framework: net8.0
dotnetVersion: "8.0.x"

Expand All @@ -30,11 +27,6 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Setup dotnet 6.0.x
uses: actions/setup-dotnet@v4
with:
dotnet-version: 6.0.x

- name: Setup dotnet 8.0.x
uses: actions/setup-dotnet@v4
with:
Expand All @@ -59,12 +51,9 @@ jobs:
runs-on: windows-latest
strategy:
matrix:
framework: [net6.0, net8.0, net472, net9.0]
framework: [net8.0, net472, net9.0]

include:
- framework: net6.0
dotnetVersion: "6.0.x"

- framework: net8.0
dotnetVersion: "8.0.x"

Expand All @@ -73,11 +62,6 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Setup dotnet 6.0.x
uses: actions/setup-dotnet@v4
with:
dotnet-version: 6.0.x

- name: Setup dotnet 8.0.x
uses: actions/setup-dotnet@v4
with:
Expand Down Expand Up @@ -127,13 +111,10 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
framework: [net6.0, net8.0, net9.0]
framework: [net8.0, net9.0]
project: [App, Tests, ProjectWithReferenceContainingLicenseExpression]

include:
- framework: net6.0
dotnetVersion: "6.0.x"

- framework: net8.0
dotnetVersion: "8.0.x"

Expand Down Expand Up @@ -218,12 +199,9 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
framework: [net6.0, net8.0, net9.0]
framework: [net8.0, net9.0]

include:
- framework: net6.0
dotnetVersion: "6.0.x"

- framework: net8.0
dotnetVersion: "8.0.x"

Expand Down
6 changes: 0 additions & 6 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ jobs:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Setup dotnet 6.0.x
uses: actions/setup-dotnet@v4
with:
dotnet-version: "6.0.x"
- name: Setup dotnet 8.0.x
uses: actions/setup-dotnet@v4
with:
Expand Down Expand Up @@ -54,8 +50,6 @@ jobs:
echo "publish to path: $path"
echo "path=$path" >> $env:GITHUB_OUTPUT
- name: Publish the application binaries (.net6)
run: dotnet publish ./src/NuGetLicenseCore/NuGetLicenseCore.csproj -c Release --no-restore -o ${{ steps.artifacts_path.outputs.path }}/net6 -f net6.0 -p:Version=${{ steps.version.outputs.full_without_prefix }}
- name: Publish the application binaries (.net8)
run: dotnet publish ./src/NuGetLicenseCore/NuGetLicenseCore.csproj -c Release --no-restore -o ${{ steps.artifacts_path.outputs.path }}/net8 -f net8.0 -p:Version=${{ steps.version.outputs.full_without_prefix }}
- name: Publish the application binaries (.net9)
Expand Down
2 changes: 1 addition & 1 deletion src/NuGetLicenseCore/NuGetLicenseCore.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net6.0;net8.0;net9.0</TargetFrameworks>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
<IsPackable>true</IsPackable>
<PackAsTool>true</PackAsTool>
<PackageType>DotnetTool</PackageType>
Expand Down
13 changes: 13 additions & 0 deletions src/NuGetUtility/Extensions/TaskExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Licensed to the projects contributors.
// The license conditions are provided in the LICENSE file located in the project root

namespace NuGetUtility.Extensions
{
public static class TaskExtensions
{
public static async Task<IEnumerable<T1>> SelectManyAsync<T, T1>(this IEnumerable<T> enumeration, Func<T, Task<IEnumerable<T1>>> func)
{
return (await Task.WhenAll(enumeration.Select(func))).SelectMany(s => s);
}
}
}
3 changes: 2 additions & 1 deletion src/NuGetUtility/NuGetUtility.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net472;net6.0;net8.0;net9.0</TargetFrameworks>
<TargetFrameworks>net472;net8.0;net9.0</TargetFrameworks>
<RepositoryType>git</RepositoryType>
<Version>100.100.100</Version>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
Expand All @@ -27,6 +27,7 @@
<ItemGroup>
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="4.1.1" />
<PackageReference Include="Microsoft.Build.Locator" Version="1.7.8" />
<PackageReference Include="Microsoft.VisualStudio.SolutionPersistence" Version="1.0.28" />
<PackageReference Include="NuGet.Commands" Version="6.12.1" />
<PackageReference Include="NuGet.Packaging" Version="6.12.1" />
<PackageReference Include="Tethys.SPDX.ExpressionParser" Version="2.1.2" />
Expand Down
2 changes: 1 addition & 1 deletion src/NuGetUtility/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ private async Task<int> OnExecuteAsync(CancellationToken cancellationToken)
ignoredPackages);

string[] excludedProjects = GetExcludedProjects();
IEnumerable<string> projects = inputFiles.SelectMany(projectCollector.GetProjects).Where(p => !Array.Exists(excludedProjects, ignored => p.Like(ignored)));
IEnumerable<string> projects = (await inputFiles.SelectManyAsync(projectCollector.GetProjectsAsync)).Where(p => !Array.Exists(excludedProjects, ignored => p.Like(ignored)));
IEnumerable<ProjectWithReferencedPackages> packagesForProject = GetPackagesPerProject(projects, projectReader, out IReadOnlyCollection<Exception>? projectReaderExceptions);
IAsyncEnumerable<ReferencedPackageWithContext> downloadedLicenseInformation =
packagesForProject.SelectMany(p => GetPackageInformations(p, overridePackageInformation, cancellationToken));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ public ProjectsCollector(IMsBuildAbstraction msBuild)
_msBuild = msBuild;
}

public IEnumerable<string> GetProjects(string inputPath)
public async Task<IEnumerable<string>> GetProjectsAsync(string inputPath)
{
return Path.GetExtension(inputPath).Equals(".sln")
? _msBuild.GetProjectsFromSolution(Path.GetFullPath(inputPath)).Where(File.Exists).Select(Path.GetFullPath)
return Path.GetExtension(inputPath).StartsWith(".sln")
? (await _msBuild.GetProjectsFromSolutionAsync(Path.GetFullPath(inputPath))).Where(File.Exists).Select(Path.GetFullPath)
: new[] { Path.GetFullPath(inputPath) };
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ namespace NuGetUtility.Wrapper.MsBuildWrapper
public interface IMsBuildAbstraction
{
IProject GetProject(string projectPath);
IEnumerable<string> GetProjectsFromSolution(string inputPath);
Task<IEnumerable<string>> GetProjectsFromSolutionAsync(string inputPath);
}
}
12 changes: 7 additions & 5 deletions src/NuGetUtility/Wrapper/MsBuildWrapper/MsBuildAbstraction.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// Licensed to the projects contributors.
// The license conditions are provided in the LICENSE file located in the project root

using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Locator;
using Microsoft.VisualStudio.SolutionPersistence;
using Microsoft.VisualStudio.SolutionPersistence.Serializer;

namespace NuGetUtility.Wrapper.MsBuildWrapper
{
Expand Down Expand Up @@ -32,11 +33,12 @@ public IProject GetProject(string projectPath)
return new ProjectWrapper(project);
}

public IEnumerable<string> GetProjectsFromSolution(string inputPath)
public async Task<IEnumerable<string>> GetProjectsFromSolutionAsync(string inputPath)
{
string absolutePath = Path.IsPathRooted(inputPath) ? inputPath : Path.Combine(Environment.CurrentDirectory, inputPath);
var sln = SolutionFile.Parse(absolutePath);
return sln.ProjectsInOrder.Select(p => p.AbsolutePath);
ISolutionSerializer serializer = SolutionSerializers.GetSerializerByMoniker(inputPath) ?? throw new MsBuildAbstractionException("Failed to determine serializer for solution");

Microsoft.VisualStudio.SolutionPersistence.Model.SolutionModel model = await serializer.OpenAsync(inputPath, CancellationToken.None);
return model.SolutionProjects.Select(p => p.FilePath);
}

private static void RegisterMsBuildLocatorIfNeeded()
Expand Down
2 changes: 1 addition & 1 deletion tests/NuGetUtility.Test/NuGetUtility.Test.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net472;net6.0;net8.0;net9.0</TargetFrameworks>
<TargetFrameworks>net472;net8.0;net9.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1 +1 @@
{SolutionDirectory}tests/targets/PackageReferenceProject/PackageReferenceProject.csproj,{SolutionDirectory}tests/targets/PackagesConfigProject/PackagesConfigProject.csproj,{SolutionDirectory}tests/targets/ProjectWithoutNugetReferences/ProjectWithoutNugetReferences.csproj,{SolutionDirectory}tests/targets/ProjectWithTransitiveNuget/ProjectWithTransitiveNuget.csproj,{SolutionDirectory}tests/targets/ProjectWithTransitiveReferences/ProjectWithTransitiveReferences.csproj
PackageReferenceProject/PackageReferenceProject.csproj,PackagesConfigProject/PackagesConfigProject.csproj,ProjectWithoutNugetReferences/ProjectWithoutNugetReferences.csproj,ProjectWithTransitiveNuget/ProjectWithTransitiveNuget.csproj,ProjectWithTransitiveReferences/ProjectWithTransitiveReferences.csproj
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{SolutionDirectory}tests/targets/PackageReferenceProject/PackageReferenceProject.csproj,{SolutionDirectory}tests/targets/PackagesConfigProject/PackagesConfigProject.csproj,{SolutionDirectory}tests/targets/ProjectWithoutNugetReferences/ProjectWithoutNugetReferences.csproj,{SolutionDirectory}tests/targets/ProjectWithTransitiveNuget/ProjectWithTransitiveNuget.csproj,{SolutionDirectory}tests/targets/ProjectWithTransitiveReferences/ProjectWithTransitiveReferences.csproj
PackageReferenceProject/PackageReferenceProject.csproj,PackagesConfigProject/PackagesConfigProject.csproj,ProjectWithoutNugetReferences/ProjectWithoutNugetReferences.csproj,ProjectWithTransitiveNuget/ProjectWithTransitiveNuget.csproj,ProjectWithTransitiveReferences/ProjectWithTransitiveReferences.csproj
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{SolutionDirectory}tests\targets\PackageReferenceProject\PackageReferenceProject.csproj,{SolutionDirectory}tests\targets\PackagesConfigProject\PackagesConfigProject.csproj,{SolutionDirectory}tests\targets\ProjectWithoutNugetReferences\ProjectWithoutNugetReferences.csproj,{SolutionDirectory}tests\targets\ProjectWithTransitiveNuget\ProjectWithTransitiveNuget.csproj,{SolutionDirectory}tests\targets\ProjectWithTransitiveReferences\ProjectWithTransitiveReferences.csproj
PackageReferenceProject\PackageReferenceProject.csproj,PackagesConfigProject\PackagesConfigProject.csproj,ProjectWithoutNugetReferences\ProjectWithoutNugetReferences.csproj,ProjectWithTransitiveNuget\ProjectWithTransitiveNuget.csproj,ProjectWithTransitiveReferences\ProjectWithTransitiveReferences.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
../ProjectWithTransitiveNuget/ProjectWithTransitiveNuget.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
../ProjectWithTransitiveNuget/ProjectWithTransitiveNuget.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
..\ProjectWithTransitiveNuget\ProjectWithTransitiveNuget.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -34,97 +34,102 @@ public void SetUp()
[TestCase("B.fsproj")]
[TestCase("C.vbproj")]
[TestCase("D.dbproj")]
public void GetProjects_Should_ReturnProjectsAsListDirectly(string projectFile)
public async Task GetProjects_Should_ReturnProjectsAsListDirectly(string projectFile)
{
IEnumerable<string> result = _uut.GetProjects(projectFile);
IEnumerable<string> result = await _uut.GetProjectsAsync(projectFile);
Assert.That(result, Is.EqualTo(new[] { Path.GetFullPath(projectFile) }));
_msBuild.DidNotReceive().GetProjectsFromSolution(Arg.Any<string>());
await _msBuild.DidNotReceive().GetProjectsFromSolutionAsync(Arg.Any<string>());
}

[TestCase("A.sln")]
[TestCase("B.sln")]
[TestCase("C.sln")]
public void GetProjects_Should_QueryMsBuildToGetProjectsForSolutionFiles(string solutionFile)
[TestCase("A.slnx")]
public async Task GetProjects_Should_QueryMsBuildToGetProjectsForSolutionFiles(string solutionFile)
{
_ = _uut.GetProjects(solutionFile);
_ = await _uut.GetProjectsAsync(solutionFile);

_msBuild.Received(1).GetProjectsFromSolution(Path.GetFullPath(solutionFile));
await _msBuild.Received(1).GetProjectsFromSolutionAsync(Path.GetFullPath(solutionFile));
}

[TestCase("A.sln")]
[TestCase("B.sln")]
[TestCase("C.sln")]
public void GetProjects_Should_ReturnEmptyArray_If_SolutionContainsNoProjects(string solutionFile)
[TestCase("C.slnx")]
public async Task GetProjects_Should_ReturnEmptyArray_If_SolutionContainsNoProjects(string solutionFile)
{
_msBuild.GetProjectsFromSolution(Arg.Any<string>()).Returns(Enumerable.Empty<string>());
_msBuild.GetProjectsFromSolutionAsync(Arg.Any<string>()).Returns(Task.FromResult(Enumerable.Empty<string>()));

IEnumerable<string> result = _uut.GetProjects(solutionFile);
IEnumerable<string> result = await _uut.GetProjectsAsync(solutionFile);
Assert.That(result, Is.Empty);

_msBuild.Received(1).GetProjectsFromSolution(Path.GetFullPath(solutionFile));
await _msBuild.Received(1).GetProjectsFromSolutionAsync(Path.GetFullPath(solutionFile));
}

[TestCase("A.sln")]
[TestCase("B.sln")]
[TestCase("C.sln")]
public void GetProjects_Should_ReturnEmptyArray_If_SolutionContainsProjectsThatDontExist(string solutionFile)
[TestCase("B.slnx")]
public async Task GetProjects_Should_ReturnEmptyArray_If_SolutionContainsProjectsThatDontExist(string solutionFile)
{
IEnumerable<string> projects = _fixture.CreateMany<string>();
_msBuild.GetProjectsFromSolution(Arg.Any<string>()).Returns(projects);
_msBuild.GetProjectsFromSolutionAsync(Arg.Any<string>()).Returns(Task.FromResult(projects));

IEnumerable<string> result = _uut.GetProjects(solutionFile);
IEnumerable<string> result = await _uut.GetProjectsAsync(solutionFile);
Assert.That(result, Is.Empty);

_msBuild.Received(1).GetProjectsFromSolution(Path.GetFullPath(solutionFile));
await _msBuild.Received(1).GetProjectsFromSolutionAsync(Path.GetFullPath(solutionFile));
}

[TestCase("A.sln")]
[TestCase("B.sln")]
[TestCase("C.sln")]
public void GetProjects_Should_ReturnArrayOfProjects_If_SolutionContainsProjectsThatDoExist(string solutionFile)
[TestCase("C.slnx")]
public async Task GetProjects_Should_ReturnArrayOfProjects_If_SolutionContainsProjectsThatDoExist(string solutionFile)
{
string[] projects = _fixture.CreateMany<string>().ToArray();
CreateFiles(projects);
_msBuild.GetProjectsFromSolution(Arg.Any<string>()).Returns(projects);
_msBuild.GetProjectsFromSolutionAsync(Arg.Any<string>()).Returns(Task.FromResult<IEnumerable<string>>(projects));

IEnumerable<string> result = _uut.GetProjects(solutionFile);
IEnumerable<string> result = await _uut.GetProjectsAsync(solutionFile);
Assert.That(result, Is.EqualTo(projects.Select(Path.GetFullPath)));

_msBuild.Received(1).GetProjectsFromSolution(Path.GetFullPath(solutionFile));
await _msBuild.Received(1).GetProjectsFromSolutionAsync(Path.GetFullPath(solutionFile));
}

[TestCase("A.sln")]
[TestCase("B.sln")]
[TestCase("C.sln")]
public void GetProjects_Should_ReturnOnlyExistingProjectsInSolutionFile(string solutionFile)
[TestCase("A.slnx")]
public async Task GetProjects_Should_ReturnOnlyExistingProjectsInSolutionFile(string solutionFile)
{
string[] existingProjects = _fixture.CreateMany<string>().ToArray();
IEnumerable<string> missingProjects = _fixture.CreateMany<string>();

CreateFiles(existingProjects);

_msBuild.GetProjectsFromSolution(Arg.Any<string>())
_msBuild.GetProjectsFromSolutionAsync(Arg.Any<string>())
.Returns(existingProjects.Concat(missingProjects).Shuffle(54321));

IEnumerable<string> result = _uut.GetProjects(solutionFile);
IEnumerable<string> result = await _uut.GetProjectsAsync(solutionFile);
Assert.That(result, Is.EquivalentTo(existingProjects.Select(Path.GetFullPath)));

_msBuild.Received(1).GetProjectsFromSolution(Path.GetFullPath(solutionFile));
await _msBuild.Received(1).GetProjectsFromSolutionAsync(Path.GetFullPath(solutionFile));
}

[Test]
public async Task GetProjectsFromSolution_Should_ReturnProjectsInActualSolutionFileRelativePath()
{
var msbuild = new MsBuildAbstraction();
IEnumerable<string> result = msbuild.GetProjectsFromSolution("../../../../targets/Projects.sln");
IEnumerable<string> result = await msbuild.GetProjectsFromSolutionAsync("../../../../targets/Projects.sln");
await Verify(string.Join(",", result), _osPlatformSpecificVerifySettings);
}

[Test]
public async Task GetProjectsFromSolution_Should_ReturnProjectsInActualSolutionFileAbsolutePath()
public async Task GetProjectsFromXmlSolution_Should_ReturnProjectsInActualSolutionFileRelativePath()
{
var msbuild = new MsBuildAbstraction();
IEnumerable<string> result = msbuild.GetProjectsFromSolution(Path.GetFullPath("../../../../targets/Projects.sln"));
IEnumerable<string> result = await msbuild.GetProjectsFromSolutionAsync("../../../../targets/slnx/slnx.slnx");
await Verify(string.Join(",", result), _osPlatformSpecificVerifySettings);
}

Expand Down
Loading

0 comments on commit 6606dcb

Please sign in to comment.