Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
2ffcb2d
Update CPM
joeloff Aug 13, 2025
60a4564
Update DTF references
joeloff Aug 13, 2025
36db5c1
Update .editorconfig for WiX
joeloff Aug 13, 2025
ded45f5
Remove variables.wxi
joeloff Aug 13, 2025
d174463
Update packages references for workloads project
joeloff Aug 13, 2025
42de590
Add wixproj project stub
joeloff Aug 13, 2025
7a1e989
Fix using statements
joeloff Aug 13, 2025
35259fa
Add .wixproj to embedded templates
joeloff Aug 13, 2025
2283176
Add WiX Project
joeloff Aug 28, 2025
3a754e8
Update manifest MSI
joeloff Sep 2, 2025
710c253
Merge branch 'main' into workloads-wix5
joeloff Sep 2, 2025
ede0f6e
Rewrite some tests for manifests/pack MSIs
joeloff Sep 4, 2025
a5a90dc
Fix unit tests, disable pack groups
joeloff Sep 16, 2025
75c9ed0
Add support for generating wixpacks
joeloff Sep 17, 2025
cdd7984
Update workload set authoring and tests
joeloff Sep 19, 2025
a0af372
Convert workload pack groups to WiX 5
joeloff Dec 3, 2025
73ca430
Merge branch 'main' into workloads-wix5
joeloff Dec 3, 2025
29b32c6
Add verification for workload pack group test
joeloff Dec 4, 2025
41daee0
Unit tests for pack groups, minor cleanup
joeloff Dec 8, 2025
a92c59b
Add size check for MSI
joeloff Dec 9, 2025
0994daa
Fix toolset info generation
joeloff Dec 9, 2025
1d99352
Test clean up, address helix failures
joeloff Dec 9, 2025
4300620
Separate tests to avoid shared access
joeloff Dec 10, 2025
9c7872b
cleanup, start removing HEAT dependencies
joeloff Feb 11, 2026
3ff2cfc
Merge branch 'main' into workloads-wix5
joeloff Feb 11, 2026
c3bb814
Refactor manifest MSIs generation
joeloff Feb 14, 2026
5aee93c
More refactoring
joeloff Feb 18, 2026
2737c5b
Simplify directories for manifest installers
joeloff Feb 18, 2026
ba76d91
Update workload sets
joeloff Feb 18, 2026
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
4 changes: 4 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ tab_width = 2
indent_size = 4
tab_width = 4

# WiX files
[*.{wixproj,wxs,wxi,wxl,thm}]
indent_size = 2

# New line preferences
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
Expand Down
7 changes: 6 additions & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,13 @@
<PackageVersion Include="Microsoft.OpenApi" Version="1.3.2" />
<PackageVersion Include="Microsoft.OpenApi.Readers" Version="1.3.2" />
<PackageVersion Include="Microsoft.Signed.Wix" Version="$(MicrosoftSignedWixVersion)" />
<PackageVersion Include="Microsoft.WixToolset.Sdk" Version="$(MicrosoftWixToolsetSdkVersion)" />
<PackageVersion Include="Microsoft.VisualStudio.OLE.Interop" Version="7.10.6071" />
<PackageVersion Include="Microsoft.WixToolset.Dtf.Compression" Version="$(MicrosoftWixToolsetSdkVersion)" />
<PackageVersion Include="Microsoft.WixToolset.Dtf.Compression.Cab" Version="$(MicrosoftWixToolsetSdkVersion)" />
<PackageVersion Include="Microsoft.WixToolset.Dtf.Resources" Version="$(MicrosoftWixToolsetSdkVersion)" />
<PackageVersion Include="Microsoft.WixToolset.Dtf.WindowsInstaller" Version="$(MicrosoftWixToolsetSdkVersion)" />
<PackageVersion Include="Microsoft.WixToolset.Dtf.WindowsInstaller.Package" Version="$(MicrosoftWixToolsetSdkVersion)" />
<PackageVersion Include="Microsoft.WixToolset.Sdk" Version="$(MicrosoftWixToolsetSdkVersion)" />
<PackageVersion Include="Mono.Options" Version="5.3.0.1" />
<PackageVersion Include="Moq" Version="4.18.4" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,77 +8,108 @@
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Microsoft.DotNet.Build.Tasks.Workloads.Msi;
using WixToolset.Dtf.WindowsInstaller;
using Xunit;

namespace Microsoft.DotNet.Build.Tasks.Workloads.Tests
{
public class CreateVisualStudioWorkloadSetTests : TestBase
{
[WindowsOnlyFact]
public static void ItCanCreateWorkloadSets()
public void ItCanCreateWorkloadSets()
{
// Create intermediate outputs under %temp% to avoid path issues and make sure it's clean so we don't pick up
// conflicting sources from previous runs.
string baseIntermediateOutputPath = Path.Combine(Path.GetTempPath(), "WLS");
string testCaseDirectory = GetTestCaseDirectory();
string baseIntermediateOutputPath = testCaseDirectory;

if (Directory.Exists(baseIntermediateOutputPath))
{
Directory.Delete(baseIntermediateOutputPath, recursive: true);
}

ITaskItem[] workloadSetPackages = new[]
{
ITaskItem[] workloadSetPackages =
[
new TaskItem(Path.Combine(TestAssetsPath, "microsoft.net.workloads.9.0.100.9.0.100-baseline.1.23464.1.nupkg"))
.WithMetadata(Metadata.MsiVersion, "12.8.45")
};
];

IBuildEngine buildEngine = new MockBuildEngine();
var buildEngine = new MockBuildEngine();

CreateVisualStudioWorkloadSet createWorkloadSetTask = new CreateVisualStudioWorkloadSet()
{
BaseOutputPath = BaseOutputPath,
BaseOutputPath = Path.Combine(testCaseDirectory, "msi"),
BaseIntermediateOutputPath = baseIntermediateOutputPath,
BuildEngine = buildEngine,
OverridePackageVersions = true,
WixToolsetPath = WixToolsetPath,
WorkloadSetPackageFiles = workloadSetPackages
};

Assert.True(createWorkloadSetTask.Execute());
Assert.True(createWorkloadSetTask.Execute(), buildEngine.BuildErrorEvents.Count > 0 ?
buildEngine.BuildErrorEvents[0].Message : "Task failed. No error events");

// Validate the arm64 installer.
ITaskItem arm64Msi = createWorkloadSetTask.Msis.FirstOrDefault(i => i.GetMetadata(Metadata.Platform) == "arm64");
Assert.NotNull(arm64Msi);
ITaskItem x64Msi = createWorkloadSetTask.Msis.FirstOrDefault(i => i.GetMetadata(Metadata.Platform) == "x64");
Assert.NotNull(x64Msi);

var arm64MsiPath = arm64Msi.ItemSpec;
var x64MsiPath = x64Msi.ItemSpec;

// Spot check the x64 generated MSI.
ITaskItem msi = createWorkloadSetTask.Msis.Where(i => i.GetMetadata(Metadata.Platform) == "x64").FirstOrDefault();
Assert.NotNull(msi);
// Process the summary information stream's template to extract the MSIs target platform.
using SummaryInfo si = new(arm64MsiPath, enableWrite: false);
Assert.Equal("Arm64;1033", si.Template);

// Verify the workload set records the CLI will use.
MsiUtils.GetAllRegistryKeys(msi.ItemSpec).Should().Contain(r =>
r.Root == 2 &&
r.Key == @"SOFTWARE\Microsoft\dotnet\InstalledWorkloadSets\x64\9.0.100\9.0.100-baseline.1.23464.1" &&
r.Name == "ProductVersion" &&
r.Value == "12.8.45");
// Upgrades are not supported, but we do generated stable GUIDs based on various
// properties including the target platform.
string upgradeCode = MsiUtils.GetProperty(arm64MsiPath, MsiProperty.UpgradeCode);
Assert.Equal("{A05B88DE-F40F-3C20-B6DA-719B8EED1D9F}", upgradeCode);
// Make sure the x64 and arm64 MSIs have different UpgradeCode properties.
string x64UpgradeCode = MsiUtils.GetProperty(x64MsiPath, MsiProperty.UpgradeCode);
Assert.NotEqual(upgradeCode, x64UpgradeCode);

// Verify the installation record and dependency provider registry entries.
var registryKeys = MsiUtils.GetAllRegistryKeys(arm64MsiPath);
string productCode = MsiUtils.GetProperty(arm64MsiPath, MsiProperty.ProductCode);
string installationRecordKey = @"SOFTWARE\Microsoft\dotnet\InstalledWorkloadSets\arm64\9.0.100\9.0.100-baseline.1.23464.1";
string dependencyProviderKey = @"Software\Classes\Installer\Dependencies\Microsoft.NET.Workload.Set,9.0.100,9.0.100-baseline.1.23464.1,arm64";

// ProductCode and UpgradeCode values in the installation record should match the
// values from the Property table.
ValidateInstallationRecord(registryKeys, installationRecordKey,
"Microsoft.NET.Workload.Set,9.0.100,9.0.100-baseline.1.23464.1,arm64",
productCode, upgradeCode, "12.8.45");
ValidateDependencyProviderKey(registryKeys, dependencyProviderKey);

// Workload sets are SxS. Verify that we don't have an Upgrade table.
Assert.False(MsiUtils.HasTable(msi.ItemSpec, "Upgrade"));
// This requires suppressing the default behavior by setting Package@UpgradeStrategy to "none".
MsiUtils.HasTable(arm64MsiPath, "Upgrade").Should().BeFalse("because workload sets are side-by-side");

// Verify the workloadset version directory and only look at the long name version.
DirectoryRow versionDir = MsiUtils.GetAllDirectories(msi.ItemSpec).FirstOrDefault(d => string.Equals(d.Directory, "WorkloadSetVersionDir"));
DirectoryRow versionDir = MsiUtils.GetAllDirectories(arm64MsiPath).FirstOrDefault(d => string.Equals(d.Directory, "WorkloadSetVersionDir"));
Assert.NotNull(versionDir);
Assert.Contains("|9.0.0.100-baseline.1.23464.1", versionDir.DefaultDir);

// Verify that the workloadset.json exists.
var files = MsiUtils.GetAllFiles(arm64MsiPath);
files.Should().Contain(f => f.FileName.EndsWith("|workloadset.json"));

// Verify the SWIX authoring for one of the workload set MSIs.
ITaskItem workloadSetSwixItem = createWorkloadSetTask.SwixProjects.Where(s => s.ItemSpec.Contains(@"Microsoft.NET.Workloads.9.0.100.9.0.100-baseline.1.23464.1\x64")).FirstOrDefault();
ITaskItem workloadSetSwixItem = createWorkloadSetTask.SwixProjects.Where(s => s.ItemSpec.Contains(@"Microsoft.NET.Workloads.9.0.100.9.0.100-baseline.1.23464.1\arm64")).FirstOrDefault();
Assert.Equal(DefaultValues.PackageTypeMsiWorkloadSet, workloadSetSwixItem.GetMetadata(Metadata.PackageType));

string msiSwr = File.ReadAllText(Path.Combine(Path.GetDirectoryName(workloadSetSwixItem.ItemSpec), "msi.swr"));
Assert.Contains("package name=Microsoft.NET.Workloads.9.0.100.9.0.100-baseline.1.23464.1", msiSwr);
Assert.Contains("version=12.8.45", msiSwr);
Assert.DoesNotContain("vs.package.chip=x64", msiSwr);
Assert.Contains("vs.package.machineArch=x64", msiSwr);
Assert.DoesNotContain("vs.package.chip=arm64", msiSwr);
Assert.Contains("vs.package.machineArch=arm64", msiSwr);
Assert.Contains("vs.package.type=msi", msiSwr);

// Verify package group SWIX project
ITaskItem workloadSetPackageGroupSwixItem = createWorkloadSetTask.SwixProjects.Where(
s => s.GetMetadata(Metadata.PackageType).Equals(DefaultValues.PackageTypeWorkloadSetPackageGroup)).
FirstOrDefault();
ITaskItem workloadSetPackageGroupSwixItem = createWorkloadSetTask.SwixProjects.FirstOrDefault(
s => s.GetMetadata(Metadata.PackageType).Equals(DefaultValues.PackageTypeWorkloadSetPackageGroup));
string packageGroupSwr = File.ReadAllText(Path.Combine(Path.GetDirectoryName(workloadSetPackageGroupSwixItem.ItemSpec), "packageGroup.swr"));
Assert.Contains("package name=PackageGroup.NET.Workloads-9.0.100", packageGroupSwr);
Assert.Contains("vs.dependency id=Microsoft.NET.Workloads.9.0.100.9.0.100-baseline.1.23464.1", packageGroupSwr);
Expand Down
Loading