-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Add SelectRuntimeIdentifierSpecificItems MSBuild task for filtering items by compatible RuntimeIdentifier #50615
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
Merged
+271
−0
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
096f0e6
Initial plan
Copilot b6896c8
Implement SelectRuntimeIdentifierSpecificItems MSBuild task with tests
Copilot 3c5bc2d
Add UsingTask declaration for SelectRuntimeIdentifierSpecificItems in…
Copilot 409e5cb
Remove #nullable disable and add proper nullable reference type annot…
Copilot 0bfc5af
Simplify runtime compatibility check to use runtimeGraph.AreCompatibl…
Copilot c81f323
Update nullable annotations for Required properties to use null! pattern
Copilot c3e81c1
Address Yanni's formatting feedback
baronfel File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
191 changes: 191 additions & 0 deletions
191
src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenASelectRuntimeIdentifierSpecificItems.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using FluentAssertions; | ||
using Microsoft.Build.Framework; | ||
using Microsoft.Build.Utilities; | ||
using Xunit; | ||
|
||
namespace Microsoft.NET.Build.Tasks.UnitTests | ||
{ | ||
public class GivenASelectRuntimeIdentifierSpecificItems | ||
{ | ||
[Fact] | ||
public void ItSelectsCompatibleItems() | ||
{ | ||
// Arrange | ||
var testRuntimeGraphPath = CreateTestRuntimeGraph(); | ||
var items = new[] | ||
{ | ||
CreateTaskItem("Item1", "linux-x64"), | ||
CreateTaskItem("Item2", "win-x64"), | ||
CreateTaskItem("Item3", "linux"), | ||
CreateTaskItem("Item4", "ubuntu.18.04-x64") | ||
}; | ||
|
||
var task = new SelectRuntimeIdentifierSpecificItems() | ||
{ | ||
TargetRuntimeIdentifier = "ubuntu.18.04-x64", | ||
Items = items, | ||
RuntimeIdentifierGraphPath = testRuntimeGraphPath, | ||
BuildEngine = new MockBuildEngine() | ||
}; | ||
|
||
// Act | ||
bool result = task.Execute(); | ||
|
||
// Assert | ||
result.Should().BeTrue(); | ||
task.SelectedItems.Should().HaveCount(3); // linux-x64, linux, ubuntu.18.04-x64 should be compatible | ||
task.SelectedItems.Should().Contain(i => i.ItemSpec == "Item1"); // linux-x64 | ||
task.SelectedItems.Should().Contain(i => i.ItemSpec == "Item3"); // linux | ||
task.SelectedItems.Should().Contain(i => i.ItemSpec == "Item4"); // ubuntu.18.04-x64 | ||
task.SelectedItems.Should().NotContain(i => i.ItemSpec == "Item2"); // win-x64 | ||
} | ||
|
||
[Fact] | ||
public void ItSelectsItemsWithExactMatch() | ||
{ | ||
// Arrange | ||
var testRuntimeGraphPath = CreateTestRuntimeGraph(); | ||
var items = new[] | ||
{ | ||
CreateTaskItem("Item1", "win-x64"), | ||
CreateTaskItem("Item2", "linux-x64") | ||
}; | ||
|
||
var task = new SelectRuntimeIdentifierSpecificItems() | ||
{ | ||
TargetRuntimeIdentifier = "win-x64", | ||
Items = items, | ||
RuntimeIdentifierGraphPath = testRuntimeGraphPath, | ||
BuildEngine = new MockBuildEngine() | ||
}; | ||
|
||
// Act | ||
bool result = task.Execute(); | ||
|
||
// Assert | ||
result.Should().BeTrue(); | ||
task.SelectedItems.Should().HaveCount(1); | ||
task.SelectedItems[0].ItemSpec.Should().Be("Item1"); | ||
} | ||
|
||
[Fact] | ||
public void ItSkipsItemsWithoutRuntimeIdentifierMetadata() | ||
{ | ||
// Arrange | ||
var testRuntimeGraphPath = CreateTestRuntimeGraph(); | ||
var items = new[] | ||
{ | ||
CreateTaskItem("Item1", "linux-x64"), | ||
CreateTaskItem("Item2", null), // No runtime identifier | ||
CreateTaskItem("Item3", "") // Empty runtime identifier | ||
}; | ||
|
||
var task = new SelectRuntimeIdentifierSpecificItems() | ||
{ | ||
TargetRuntimeIdentifier = "linux-x64", | ||
Items = items, | ||
RuntimeIdentifierGraphPath = testRuntimeGraphPath, | ||
BuildEngine = new MockBuildEngine() | ||
}; | ||
|
||
// Act | ||
bool result = task.Execute(); | ||
|
||
// Assert | ||
result.Should().BeTrue(); | ||
task.SelectedItems.Should().HaveCount(1); | ||
task.SelectedItems[0].ItemSpec.Should().Be("Item1"); | ||
} | ||
|
||
[Fact] | ||
public void ItUsesCustomRuntimeIdentifierMetadata() | ||
{ | ||
// Arrange | ||
var testRuntimeGraphPath = CreateTestRuntimeGraph(); | ||
var item = new TaskItem("Item1"); | ||
item.SetMetadata("CustomRID", "linux-x64"); | ||
|
||
var task = new SelectRuntimeIdentifierSpecificItems() | ||
{ | ||
TargetRuntimeIdentifier = "ubuntu.18.04-x64", | ||
Items = new[] { item }, | ||
RuntimeIdentifierItemMetadata = "CustomRID", | ||
RuntimeIdentifierGraphPath = testRuntimeGraphPath, | ||
BuildEngine = new MockBuildEngine() | ||
}; | ||
|
||
// Act | ||
bool result = task.Execute(); | ||
|
||
// Assert | ||
result.Should().BeTrue(); | ||
task.SelectedItems.Should().HaveCount(1); | ||
task.SelectedItems[0].ItemSpec.Should().Be("Item1"); | ||
} | ||
|
||
[Fact] | ||
public void ItReturnsEmptyArrayWhenNoItemsProvided() | ||
{ | ||
// Arrange | ||
var testRuntimeGraphPath = CreateTestRuntimeGraph(); | ||
|
||
var task = new SelectRuntimeIdentifierSpecificItems() | ||
{ | ||
TargetRuntimeIdentifier = "linux-x64", | ||
Items = new ITaskItem[0], | ||
RuntimeIdentifierGraphPath = testRuntimeGraphPath, | ||
BuildEngine = new MockBuildEngine() | ||
}; | ||
|
||
// Act | ||
bool result = task.Execute(); | ||
|
||
// Assert | ||
result.Should().BeTrue(); | ||
task.SelectedItems.Should().BeEmpty(); | ||
} | ||
|
||
private static TaskItem CreateTaskItem(string itemSpec, string? runtimeIdentifier) | ||
{ | ||
var item = new TaskItem(itemSpec); | ||
if (!string.IsNullOrEmpty(runtimeIdentifier)) | ||
{ | ||
item.SetMetadata("RuntimeIdentifier", runtimeIdentifier); | ||
} | ||
return item; | ||
} | ||
|
||
private static string CreateTestRuntimeGraph() | ||
{ | ||
// Create a minimal runtime graph for testing | ||
var runtimeGraph = @"{ | ||
""runtimes"": { | ||
""linux"": {}, | ||
""linux-x64"": { | ||
""#import"": [""linux""] | ||
}, | ||
""ubuntu"": { | ||
""#import"": [""linux""] | ||
}, | ||
""ubuntu.18.04"": { | ||
""#import"": [""ubuntu""] | ||
}, | ||
""ubuntu.18.04-x64"": { | ||
""#import"": [""ubuntu.18.04"", ""linux-x64""] | ||
}, | ||
""win"": {}, | ||
""win-x64"": { | ||
""#import"": [""win""] | ||
} | ||
} | ||
}"; | ||
|
||
var tempFile = Path.GetTempFileName(); | ||
File.WriteAllText(tempFile, runtimeGraph); | ||
return tempFile; | ||
} | ||
} | ||
} |
78 changes: 78 additions & 0 deletions
78
src/Tasks/Microsoft.NET.Build.Tasks/SelectRuntimeIdentifierSpecificItems.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using Microsoft.Build.Framework; | ||
using NuGet.RuntimeModel; | ||
|
||
namespace Microsoft.NET.Build.Tasks; | ||
|
||
/// <summary> | ||
/// MSBuild task that filters a set of Items by matching on compatible RuntimeIdentifier. | ||
/// This task filters an Item list by those items that contain a specific Metadata that is | ||
/// compatible with a specified Runtime Identifier, according to a given RuntimeIdentifierGraph file. | ||
/// </summary> | ||
public class SelectRuntimeIdentifierSpecificItems : TaskBase | ||
{ | ||
/// <summary> | ||
/// The target runtime identifier to check compatibility against. | ||
/// </summary> | ||
[Required] | ||
public string TargetRuntimeIdentifier { get; set; } = null!; | ||
|
||
/// <summary> | ||
/// The list of candidate items to filter. | ||
/// </summary> | ||
[Required] | ||
public ITaskItem[] Items { get; set; } = null!; | ||
|
||
/// <summary> | ||
/// The name of the MSBuild metadata to check on each item. Defaults to "RuntimeIdentifier". | ||
/// </summary> | ||
public string? RuntimeIdentifierItemMetadata { get; set; } = "RuntimeIdentifier"; | ||
|
||
/// <summary> | ||
/// Path to the RuntimeIdentifierGraph file. | ||
/// </summary> | ||
[Required] | ||
public string RuntimeIdentifierGraphPath { get; set; } = null!; | ||
|
||
/// <summary> | ||
/// The filtered items that are compatible with the <see cref="TargetRuntimeIdentifier"/> | ||
/// </summary> | ||
[Output] | ||
public ITaskItem[]? SelectedItems { get; set; } | ||
|
||
protected override void ExecuteCore() | ||
{ | ||
if (Items.Length == 0) | ||
{ | ||
SelectedItems = Array.Empty<ITaskItem>(); | ||
return; | ||
} | ||
|
||
string ridMetadata = RuntimeIdentifierItemMetadata ?? "RuntimeIdentifier"; | ||
|
||
RuntimeGraph runtimeGraph = new RuntimeGraphCache(this).GetRuntimeGraph(RuntimeIdentifierGraphPath); | ||
|
||
var selectedItems = new List<ITaskItem>(); | ||
|
||
foreach (var item in Items) | ||
{ | ||
string? itemRuntimeIdentifier = item.GetMetadata(ridMetadata); | ||
|
||
if (string.IsNullOrEmpty(itemRuntimeIdentifier)) | ||
{ | ||
// Item doesn't have the runtime identifier metadata, skip it | ||
continue; | ||
} | ||
|
||
// Check if the item's runtime identifier is compatible with the target runtime identifier | ||
if (runtimeGraph.AreCompatible(TargetRuntimeIdentifier, itemRuntimeIdentifier)) | ||
{ | ||
selectedItems.Add(item); | ||
} | ||
} | ||
|
||
SelectedItems = selectedItems.ToArray(); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.