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

Implement group conditions for SDK-style projects #4247

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
997 changes: 497 additions & 500 deletions .paket/Paket.Restore.targets

Large diffs are not rendered by default.

237 changes: 237 additions & 0 deletions integrationtests/Paket.IntegrationTests/ConditionSpecs.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
module Paket.IntegrationTests.ConditionSpecs

open System.Text.RegularExpressions
open System.Xml.Linq
open System.Xml.XPath
open Fake
open System
open NUnit.Framework
open FsUnit
open System
open System.IO
open System.Diagnostics
open Paket
open Paket.Domain

let preparePackages workingDir =
let packagesDir = workingDir @@ "Packages"

[1..5]
|> List.filter (fun v -> fileExists (workingDir @@ "Packages" @@ $"PaketTest2394.PackageA.%d{v}.0.0.nupkg") |> not)
|> List.map (fun v -> directDotnet false $"pack -o . -p:Version=%d{v}.0" packagesDir)
|> ignore

let prepareBuildProps projectDir =
let propsFile = (projectDir @@ "Directory.Build.props")
let xmlDoc = XDocument.Load propsFile
let propertyGroup = xmlDoc.Descendants("PropertyGroup")
|> Seq.head
propertyGroup.Add(XElement("PaketExePath", paketToolPath |> snd))
xmlDoc.Save propsFile

let dotnetRun projectDir project configuration =
match configuration with
| Some config -> directDotnet false $"run --project %s{project} --configuration %s{config}" projectDir
| None -> directDotnet false $"run --project %s{project}" projectDir
|> Seq.map (_.Message)

let dotnetPack projectDir project configuration =
match configuration with
| Some config -> directDotnet false $"pack %s{project} --configuration %s{config} -o ." projectDir
| None -> directDotnet false $"pack %s{project} -o ." projectDir
|> ignore

let private shouldIncludeVersionedString (pattern: string) (version: int) (inputs: string seq) =
let expected = pattern.Replace("XX", version.ToString())
let regex = $"""^%s{Regex.Escape(pattern).Replace("XX", "(\d)")}$"""

inputs
|> Seq.filter (fun input -> Regex.IsMatch(input, regex))
|> Seq.iter (fun input -> Assert.That(input, Is.EqualTo expected))

let private shouldIncludePackageA v i = shouldIncludeVersionedString "PackageA XX.0" v i
let private shouldIncludePackageB v i = shouldIncludeVersionedString "PackageB XX.0 (references PackageB.Transient XX.0)" v i
let private shouldIncludePackageBTransient v i = shouldIncludeVersionedString "PackageB.Transient XX.0" v i
let private shouldIncludeConstant v i = shouldIncludeVersionedString "Constant PACKAGEA_XX set" v i

[<Test>]
let ``#2394 default group with no condition`` () =
let scenario = "i002394-group-conditions"
preparePackages (originalScenarioPath scenario)

use __ = prepare scenario
let root = scenarioTempPath scenario
let projectDir = root @@ "TestProjects"
prepareBuildProps projectDir

directPaketInPath "install" projectDir |> ignore
let output = dotnetRun projectDir "MainGroup.fsproj" None
dotnetPack projectDir "MainGroup.fsproj" None

output |> shouldIncludePackageA 1
output |> shouldIncludePackageB 1
output |> shouldIncludePackageBTransient 1
output |> shouldIncludeConstant 1

let nupkgPath = projectDir @@ "MainGroup.1.0.0.nupkg"

if File.Exists nupkgPath |> not then Assert.Fail $"Expected '%s{nupkgPath}' to exist"
let nuspec = NuGetCache.getNuSpecFromNupkg nupkgPath
let dependencies = nuspec.Dependencies.Value
|> List.map (fun (n, v, _) -> n.Name, v.Range.ToString())

let expected = [("PaketTest2394.PackageA", ">= 1.0 < 2.0"); ("PaketTest2394.PackageB", ">= 1.0 < 2.0")]
Assert.That(dependencies, Is.SupersetOf expected)

[<Test>]
let ``#2394 alternate group with no condition`` () =
let scenario = "i002394-group-conditions"
preparePackages (originalScenarioPath scenario)

use __ = prepare scenario
let root = scenarioTempPath scenario
let projectDir = root @@ "TestProjects"
prepareBuildProps projectDir

directPaketInPath "install" projectDir |> ignore
let output = dotnetRun projectDir "NonConditionalGroup.fsproj" None
dotnetPack projectDir "NonConditionalGroup.fsproj" None

output |> shouldIncludePackageA 2
output |> shouldIncludePackageB 2
output |> shouldIncludePackageBTransient 2
output |> shouldIncludeConstant 2

let nupkgPath = projectDir @@ "NonConditionalGroup.1.0.0.nupkg"

if File.Exists nupkgPath |> not then Assert.Fail $"Expected '%s{nupkgPath}' to exist"
let nuspec = NuGetCache.getNuSpecFromNupkg nupkgPath
let dependencies = nuspec.Dependencies.Value
|> List.map (fun (n, v, _) -> n.Name, v.Range.ToString())

let expected = [("PaketTest2394.PackageA", ">= 2.0 < 3.0"); ("PaketTest2394.PackageB", ">= 2.0 < 3.0")]
Assert.That(dependencies, Is.SupersetOf expected)

[<Test>]
let ``#2394 group with fixed property condition`` () =
let scenario = "i002394-group-conditions"
preparePackages (originalScenarioPath scenario)

use __ = prepare scenario
let root = scenarioTempPath scenario
let projectDir = root @@ "TestProjects"
prepareBuildProps projectDir

directPaketInPath "install" projectDir |> ignore
let output = dotnetRun projectDir "FixedProperty.fsproj" None
dotnetPack projectDir "FixedProperty.fsproj" None

output |> shouldIncludePackageA 3
output |> shouldIncludePackageB 3
output |> shouldIncludePackageBTransient 3
output |> shouldIncludeConstant 3

let nupkgPath = projectDir @@ "FixedProperty.1.0.0.nupkg"

if File.Exists nupkgPath |> not then Assert.Fail $"Expected '%s{nupkgPath}' to exist"
let nuspec = NuGetCache.getNuSpecFromNupkg nupkgPath
let dependencies = nuspec.Dependencies.Value
|> List.map (fun (n, v, _) -> n.Name, v.Range.ToString())

let expected = [("PaketTest2394.PackageA", ">= 3.0 < 4.0"); ("PaketTest2394.PackageB", ">= 3.0 < 4.0")]
Assert.That(dependencies, Is.SupersetOf expected)

[<Test>]
let ``#2394 mix dependencies from multiple groups with conditions`` () =
let scenario = "i002394-group-conditions"
preparePackages (originalScenarioPath scenario)

use __ = prepare scenario
let root = scenarioTempPath scenario
let projectDir = root @@ "TestProjects"
prepareBuildProps projectDir

directPaketInPath "install" projectDir |> ignore
let output = dotnetRun projectDir "MixedProperties.fsproj" None
dotnetPack projectDir "MixedProperties.fsproj" None

output |> shouldIncludePackageA 4
output |> shouldIncludePackageB 5
output |> shouldIncludePackageBTransient 5
output |> shouldIncludeConstant 4

let expected = ["PackageA 4.0"; "PackageB 5.0 (references PackageB.Transient 5.0)"; "PackageB.Transient 5.0"; "Constant PACKAGEA_4 set"]
let rejected = ["PackageA 1.0"; "PackageB.Transient 1.0"; "Constant PACKAGEA_1 set"
"PackageA 2.0"; "PackageB.Transient 2.0"; "Constant PACKAGEA_2 set"
"PackageA 3.0"; "PackageB.Transient 3.0"; "Constant PACKAGEA_3 set"
"PackageA 5.0"; "PackageB.Transient 4.0"; "Constant PACKAGEA_5 set"]
Assert.That(output, Is.SupersetOf expected)
Assert.That(output, Is.Not.SubsetOf rejected)

let nupkgPath = projectDir @@ "MixedProperties.1.0.0.nupkg"

if File.Exists nupkgPath |> not then Assert.Fail $"Expected '%s{nupkgPath}' to exist"
let nuspec = NuGetCache.getNuSpecFromNupkg nupkgPath
let dependencies = nuspec.Dependencies.Value
|> List.map (fun (n, v, _) -> n.Name, v.Range.ToString())

let expected = [("PaketTest2394.PackageA", ">= 4.0 < 5.0"); ("PaketTest2394.PackageB", ">= 5.0 < 6.0")]
Assert.That(dependencies, Is.SupersetOf expected)

[<Test>]
let ``#2394 project with dynamic condition based on configuration 1`` () =
let scenario = "i002394-group-conditions"
preparePackages (originalScenarioPath scenario)

use __ = prepare scenario
let root = scenarioTempPath scenario
let projectDir = root @@ "TestProjects"
prepareBuildProps projectDir

directPaketInPath "install" projectDir |> ignore
let output = dotnetRun projectDir "ConfigurationDependent.fsproj" None
dotnetPack projectDir "ConfigurationDependent.fsproj" None

output |> shouldIncludePackageA 3
output |> shouldIncludePackageB 3
output |> shouldIncludePackageBTransient 3
output |> shouldIncludeConstant 3

let nupkgPath = projectDir @@ "ConfigurationDependent.1.0.0.nupkg"

if File.Exists nupkgPath |> not then Assert.Fail $"Expected '%s{nupkgPath}' to exist"
let nuspec = NuGetCache.getNuSpecFromNupkg nupkgPath
let dependencies = nuspec.Dependencies.Value
|> List.map (fun (n, v, _) -> n.Name, v.Range.ToString())

let expected = [("PaketTest2394.PackageA", ">= 3.0 < 4.0"); ("PaketTest2394.PackageB", ">= 3.0 < 4.0")]
Assert.That(dependencies, Is.SupersetOf expected)

[<Test>]
let ``#2394 project with dynamic condition based on configuration 2`` () =
let scenario = "i002394-group-conditions"
preparePackages (originalScenarioPath scenario)

use __ = prepare scenario
let root = scenarioTempPath scenario
let projectDir = root @@ "TestProjects"
prepareBuildProps projectDir

directPaketInPath "install" projectDir |> ignore
let output = dotnetRun projectDir "ConfigurationDependent.fsproj" (Some "Alternate")
dotnetPack projectDir "ConfigurationDependent.fsproj" (Some "Alternate")

output |> shouldIncludePackageA 4
output |> shouldIncludePackageB 4
output |> shouldIncludePackageBTransient 4
output |> shouldIncludeConstant 4

let nupkgPath = projectDir @@ "ConfigurationDependent.1.0.0.nupkg"

if File.Exists nupkgPath |> not then Assert.Fail $"Expected '%s{nupkgPath}' to exist"
let nuspec = NuGetCache.getNuSpecFromNupkg nupkgPath
let dependencies = nuspec.Dependencies.Value
|> List.map (fun (n, v, _) -> n.Name, v.Range.ToString())

let expected = [("PaketTest2394.PackageA", ">= 4.0 < 5.0"); ("PaketTest2394.PackageB", ">= 4.0 < 5.0")]
Assert.That(dependencies, Is.SupersetOf expected)
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
<None Include="paket.references" />
<Content Include="App.config" />
<Compile Include="AddGithubSpecs.fs" />
<Compile Include="ConditionSpecs.fs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Paket.Core\Paket.Core.fsproj" />
Expand All @@ -51,4 +52,4 @@
</Reference>
</ItemGroup>
<Import Project="..\..\.paket\Paket.Restore.targets" />
</Project>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.nupkg
bin/
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project>
<!-- Based on https://github.com/NuGet/Home/issues/5525#issuecomment-1179525536 -->
<Target Name="UseExplicitPackageVersions" BeforeTargets="GenerateNuspec">
<ItemGroup>
<_ProjectReferenceWithExplicitPackageVersion Include="@(ProjectReference->'%(FullPath)')" Condition="'%(ProjectReference.PackageVersion)' != ''" />
<_ProjectReferenceWithExactPackageVersion Include="@(ProjectReference->'%(FullPath)')" />
<_ProjectReferenceWithReassignedVersion Include="@(_ProjectReferencesWithVersions)" Condition="'%(Identity)' != '' And '@(_ProjectReferenceWithExplicitPackageVersion)' == '@(_ProjectReferencesWithVersions)'">
<ProjectVersion>@(_ProjectReferenceWithExplicitPackageVersion->'%(PackageVersion)')</ProjectVersion>
</_ProjectReferenceWithReassignedVersion>
<_ProjectReferenceWithReassignedVersion Include="@(_ProjectReferencesWithVersions)" Condition="'%(Identity)' != '' And '@(_ProjectReferenceWithExactPackageVersion)' == '@(_ProjectReferencesWithVersions)'">
<ProjectVersion>[@(_ProjectReferencesWithVersions->'%(ProjectVersion)')]</ProjectVersion>
</_ProjectReferenceWithReassignedVersion>
<_ProjectReferencesWithVersions Remove="@(_ProjectReferenceWithReassignedVersion)" />
<_ProjectReferencesWithVersions Include="@(_ProjectReferenceWithReassignedVersion)" />
</ItemGroup>
</Target>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PaketTest2394.PackageA", "PaketTest2394.PackageA\PaketTest2394.PackageA.csproj", "{A0449AB0-A1EA-4BE6-8D03-701BC5A2FD46}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PaketTest2394.PackageB", "PaketTest2394.PackageB\PaketTest2394.PackageB.csproj", "{59B3FFCE-AA5A-4AAA-B73D-108A6A15E524}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PaketTest2394.PackageB.Transient", "PaketTest2394.PackageB.Transient\PaketTest2394.PackageB.Transient.csproj", "{C763B8F6-18BF-4018-B852-CA8EE39C94F5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A0449AB0-A1EA-4BE6-8D03-701BC5A2FD46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A0449AB0-A1EA-4BE6-8D03-701BC5A2FD46}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A0449AB0-A1EA-4BE6-8D03-701BC5A2FD46}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A0449AB0-A1EA-4BE6-8D03-701BC5A2FD46}.Release|Any CPU.Build.0 = Release|Any CPU
{59B3FFCE-AA5A-4AAA-B73D-108A6A15E524}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{59B3FFCE-AA5A-4AAA-B73D-108A6A15E524}.Debug|Any CPU.Build.0 = Debug|Any CPU
{59B3FFCE-AA5A-4AAA-B73D-108A6A15E524}.Release|Any CPU.ActiveCfg = Release|Any CPU
{59B3FFCE-AA5A-4AAA-B73D-108A6A15E524}.Release|Any CPU.Build.0 = Release|Any CPU
{C763B8F6-18BF-4018-B852-CA8EE39C94F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C763B8F6-18BF-4018-B852-CA8EE39C94F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C763B8F6-18BF-4018-B852-CA8EE39C94F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C763B8F6-18BF-4018-B852-CA8EE39C94F5}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace PaketTest2394.PackageA;

public static class PackageDescription
{
public static string GetDescription()
{
var assemblyName = typeof(PackageDescription).Assembly.GetName();
return $"PackageA {assemblyName.Version!.ToString(2)}";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<None Include="build/PaketTest2394.PackageA.targets" Pack="true" PackagePath="build\PaketTest2394.PackageA.targets" />
</ItemGroup>
<Target Name="UpdateTargetsFile" BeforeTargets="Build">
<PropertyGroup>
<NewDefineConstants>%24(DefineConstants)%3BPACKAGEA_$(Version.Split('.')[0])</NewDefineConstants>
</PropertyGroup>
<XmlPoke XmlInputPath="build/PaketTest2394.PackageA.targets" Query="//DefineConstants" Value="$(NewDefineConstants)"/>
</Target>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<Project>
<PropertyGroup>
<DefineConstants>$(DefineConstants);PACKAGEA_5</DefineConstants>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace PaketTest2394.PackageB.Transient;

public static class PackageDescription
{
public static string GetDescription()
{
var assemblyName = typeof(PackageDescription).Assembly.GetName();
return $"PackageB.Transient {assemblyName.Version!.ToString(2)}";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace PaketTest2394.PackageB;

public static class PackageDescription
{
public static string GetDescription()
{
var assemblyName = typeof(PackageDescription).Assembly.GetName();
return $"PackageB {assemblyName.Version!.ToString(2)} (references {Transient.PackageDescription.GetDescription()})";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\PaketTest2394.PackageB.Transient\PaketTest2394.PackageB.Transient.csproj" />
</ItemGroup>

</Project>
Loading