Skip to content

Commit 08d5dd3

Browse files
authored
Merge pull request #47 from microsoft/alzollin/newline
Package Dependency now added on new line.
2 parents 2ba205d + a8a243c commit 08d5dd3

File tree

2 files changed

+102
-8
lines changed

2 files changed

+102
-8
lines changed

src/winsdk-CLI/Winsdk.Cli.Tests/PackageCommandTests.cs

Lines changed: 100 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

4+
using System.IO.Compression;
45
using System.Security.Cryptography.X509Certificates;
6+
using System.Text.RegularExpressions;
57
using Winsdk.Cli.Services;
68

79
namespace Winsdk.Cli.Tests;
@@ -14,6 +16,7 @@ public class PackageCommandTests : BaseCommandTests
1416
private IConfigService _configService = null!;
1517
private IBuildToolsService _buildToolsService = null!;
1618
private IMsixService _msixService = null!;
19+
private IWorkspaceSetupService _workspaceSetupService = null!;
1720
private ICertificateService _certificateService = null!;
1821

1922
/// <summary>
@@ -62,6 +65,7 @@ public void Setup()
6265

6366
_buildToolsService = GetRequiredService<IBuildToolsService>();
6467
_msixService = GetRequiredService<IMsixService>();
68+
_workspaceSetupService = GetRequiredService<IWorkspaceSetupService>();
6569
_certificateService = GetRequiredService<ICertificateService>();
6670
}
6771

@@ -271,7 +275,7 @@ await Assert.ThrowsExactlyAsync<DirectoryNotFoundException>(async () =>
271275
{
272276
await _msixService.CreateMsixPackageAsync(
273277
inputFolder: nonExistentDir,
274-
outputPath: null,
278+
outputPath: _tempDirectory,
275279
packageName: "TestPackage",
276280
skipPri: true,
277281
autoSign: false,
@@ -295,7 +299,7 @@ await Assert.ThrowsExactlyAsync<FileNotFoundException>(async () =>
295299
{
296300
await _msixService.CreateMsixPackageAsync(
297301
inputFolder: packageDir,
298-
outputPath: null,
302+
outputPath: _tempDirectory,
299303
packageName: "TestPackage",
300304
skipPri: true,
301305
autoSign: false,
@@ -335,7 +339,7 @@ public async Task CreateMsixPackageAsync_ExternalManifestWithAssets_CopiesManife
335339

336340
var result = await _msixService.CreateMsixPackageAsync(
337341
inputFolder: packageDir,
338-
outputPath: null,
342+
outputPath: _tempDirectory,
339343
packageName: "ExternalTestPackage",
340344
skipPri: true,
341345
autoSign: false,
@@ -375,7 +379,7 @@ public async Task CreateMsixPackageAsync_WithSigningAndMatchingPublishers_Should
375379
// Act & Assert - This should succeed because publishers match
376380
var result = await _msixService.CreateMsixPackageAsync(
377381
inputFolder: packageDir,
378-
outputPath: null,
382+
outputPath: _tempDirectory,
379383
packageName: "SigningTestPackage",
380384
skipPri: true,
381385
autoSign: true,
@@ -413,7 +417,7 @@ public async Task CreateMsixPackageAsync_WithSigningAndMismatchedPublishers_Shou
413417
{
414418
await _msixService.CreateMsixPackageAsync(
415419
inputFolder: packageDir,
416-
outputPath: null,
420+
outputPath: _tempDirectory,
417421
packageName: "MismatchedSigningTest",
418422
skipPri: true,
419423
autoSign: true,
@@ -460,7 +464,7 @@ await _certificateService.GenerateDevCertificateAsync(
460464
{
461465
await _msixService.CreateMsixPackageAsync(
462466
inputFolder: packageDir,
463-
outputPath: null,
467+
outputPath: _tempDirectory,
464468
packageName: "ExternalMismatchTest",
465469
skipPri: true,
466470
autoSign: true,
@@ -579,4 +583,94 @@ await _certificateService.GenerateDevCertificateAsync(
579583
Assert.Contains($"Error: Publisher in {manifestPath} (CN=ManifestPublisher)", ex.Message);
580584
Assert.Contains($"does not match the publisher in the certificate {certPath} (CN=CertificatePublisher)", ex.Message);
581585
}
586+
587+
[TestMethod]
588+
public async Task CreateMsixPackageAsync_WithWindowsAppSdkDependency_AddsPackageDependencyOnNewLine()
589+
{
590+
// Arrange - Create package structure with a manifest that has Dependencies but no WinAppSDK dependency
591+
var packageDir = Path.Combine(_tempDirectory, "WinAppSdkDependencyTest");
592+
Directory.CreateDirectory(packageDir);
593+
594+
File.WriteAllText(Path.Combine(packageDir, "AppxManifest.xml"), StandardTestManifestContent);
595+
596+
// Create Assets directory and files
597+
var assetsDir = Path.Combine(packageDir, "Assets");
598+
Directory.CreateDirectory(assetsDir);
599+
File.WriteAllText(Path.Combine(assetsDir, "Logo.png"), "fake png content");
600+
File.WriteAllText(Path.Combine(packageDir, "TestApp.exe"), "fake exe content");
601+
602+
// Create winsdk.yaml with Windows App SDK package to trigger dependency injection
603+
var configContent = @"packages:
604+
- name: Microsoft.WindowsAppSDK
605+
version: 2.0.250930001-experimental1";
606+
await File.WriteAllTextAsync(_configService.ConfigPath, configContent);
607+
608+
// Restore
609+
await _workspaceSetupService.SetupWorkspaceAsync(new WorkspaceSetupOptions
610+
{
611+
BaseDirectory = _tempDirectory,
612+
ConfigDir = _tempDirectory,
613+
RequireExistingConfig = true,
614+
ForceLatestBuildTools = false
615+
}, CancellationToken.None);
616+
617+
// Act - Create package (this should trigger the Windows App SDK dependency injection)
618+
var result = await _msixService.CreateMsixPackageAsync(
619+
inputFolder: packageDir,
620+
outputPath: _tempDirectory,
621+
packageName: "WinAppSdkDependencyTest",
622+
skipPri: true,
623+
autoSign: false,
624+
selfContained: false,
625+
cancellationToken: CancellationToken.None
626+
);
627+
628+
// Assert - Read the manifest from the package and verify PackageDependency is on its own line
629+
Assert.IsNotNull(result, "Result should not be null");
630+
Assert.IsTrue(File.Exists(result.MsixPath), "MSIX package file should exist");
631+
632+
// Extract and read the manifest from the created package
633+
var extractDir = Path.Combine(_tempDirectory, "extracted");
634+
Directory.CreateDirectory(extractDir);
635+
ZipFile.ExtractToDirectory(result.MsixPath, extractDir);
636+
637+
var extractedManifestPath = Path.Combine(extractDir, "AppxManifest.xml");
638+
Assert.IsTrue(File.Exists(extractedManifestPath), "Extracted manifest should exist");
639+
640+
var finalManifestContent = await File.ReadAllTextAsync(extractedManifestPath);
641+
642+
// Verify the PackageDependency exists
643+
Assert.Contains("<PackageDependency Name=\"Microsoft.WindowsAppRuntime", finalManifestContent,
644+
"Manifest should contain Windows App SDK PackageDependency");
645+
646+
// Verify it's on its own line (not on the same line as </Dependencies>)
647+
// The pattern we're checking: there should be a newline after the PackageDependency closing tag
648+
// and before the </Dependencies> tag
649+
var dependenciesSectionPattern = @"<Dependencies>.*?</Dependencies>";
650+
var dependenciesMatch = Regex.Match(finalManifestContent, dependenciesSectionPattern, RegexOptions.Singleline);
651+
Assert.IsTrue(dependenciesMatch.Success, "Should find Dependencies section");
652+
653+
var dependenciesSection = dependenciesMatch.Value;
654+
655+
// Check that PackageDependency and </Dependencies> are NOT on the same line
656+
var lines = dependenciesSection.Split('\n');
657+
var packageDependencyLine = lines.FirstOrDefault(l => l.Contains("<PackageDependency"));
658+
var closingTagLine = lines.FirstOrDefault(l => l.Trim() == "</Dependencies>");
659+
660+
Assert.IsNotNull(packageDependencyLine, "Should find PackageDependency line");
661+
Assert.IsNotNull(closingTagLine, "Should find closing Dependencies tag line");
662+
663+
// Verify they are different lines
664+
Assert.AreNotEqual(packageDependencyLine, closingTagLine,
665+
"PackageDependency and </Dependencies> should be on separate lines");
666+
667+
// Also verify proper formatting - there should be whitespace/newline between them
668+
var packageDependencyIndex = dependenciesSection.IndexOf("<PackageDependency", StringComparison.InvariantCulture);
669+
var closingBracketIndex = dependenciesSection.IndexOf("/>", packageDependencyIndex, StringComparison.InvariantCulture) + 2;
670+
var closingTagIndex = dependenciesSection.IndexOf("</Dependencies>", closingBracketIndex, StringComparison.InvariantCulture);
671+
672+
var betweenContent = dependenciesSection.Substring(closingBracketIndex, closingTagIndex - closingBracketIndex);
673+
Assert.Contains("\n", betweenContent,
674+
"There should be a newline between PackageDependency closing and </Dependencies> tag");
675+
}
582676
}

src/winsdk-CLI/Winsdk.Cli/Services/MsixService.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1323,8 +1323,8 @@ private string UpdateWindowsAppSdkDependency(string manifestContent)
13231323
else
13241324
{
13251325
// Add new dependency to existing Dependencies section
1326-
manifestContent = AppxPackageDependenciesCloseTagRegex().Replace(manifestContent, $@" <PackageDependency Name=""{winAppSdkInfo.RuntimeName}"" MinVersion=""{winAppSdkInfo.MinVersion}"" Publisher=""CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"" />
1327-
$1");
1326+
manifestContent = AppxPackageDependenciesCloseTagRegex().Replace(manifestContent, $@"
1327+
<PackageDependency Name=""{winAppSdkInfo.RuntimeName}"" MinVersion=""{winAppSdkInfo.MinVersion}"" Publisher=""CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"" />$1");
13281328

13291329
logger.LogDebug("{UISymbols} Added Windows App SDK dependency {RuntimeName} to existing Dependencies section (v{MinVersion})", UiSymbols.Add, winAppSdkInfo.RuntimeName, winAppSdkInfo.MinVersion);
13301330
}

0 commit comments

Comments
 (0)