Skip to content

Commit 7f619c0

Browse files
authored
Fix 1823 - MAR fails to parse RequiredVersion for dependencies (#1876)
1 parent bded102 commit 7f619c0

File tree

3 files changed

+72
-59
lines changed

3 files changed

+72
-59
lines changed

src/code/ContainerRegistryServerAPICalls.cs

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -698,37 +698,38 @@ internal JObject FindAllRepositories(string containerRegistryAccessToken, out Er
698698
internal Hashtable GetContainerRegistryMetadata(string packageName, string exactTagVersion, string containerRegistryAccessToken, out ErrorRecord errRecord)
699699
{
700700
_cmdletPassedIn.WriteDebug("In ContainerRegistryServerAPICalls::GetContainerRegistryMetadata()");
701-
Hashtable requiredVersionResponse = new Hashtable();
701+
Hashtable requiredVersionResponse = new();
702702

703-
var foundTags = FindContainerRegistryManifest(packageName, exactTagVersion, containerRegistryAccessToken, out errRecord);
703+
JObject foundTags = FindContainerRegistryManifest(packageName, exactTagVersion, containerRegistryAccessToken, out errRecord);
704704
if (errRecord != null)
705705
{
706706
return requiredVersionResponse;
707707
}
708708

709-
/* Response returned looks something like:
710-
* {
711-
* "schemaVersion": 2,
712-
* "config": {
713-
* "mediaType": "application/vnd.unknown.config.v1+json",
714-
* "digest": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
715-
* "size": 0
716-
* },
717-
* "layers": [
718-
* {
719-
* "mediaType": "application/vnd.oci.image.layer.nondistributable.v1.tar+gzip'",
720-
* "digest": "sha256:7c55c7b66cb075628660d8249cc4866f16e34741c246a42ed97fb23ccd4ea956",
721-
* "size": 3533,
722-
* "annotations": {
723-
* "org.opencontainers.image.title": "test_module.1.0.0.nupkg",
724-
* "metadata": "{\"GUID\":\"45219bf4-10a4-4242-92d6-9bfcf79878fd\",\"FunctionsToExport\":[],\"CompanyName\":\"Anam\",\"CmdletsToExport\":[],\"VariablesToExport\":\"*\",\"Author\":\"Anam Navied\",\"ModuleVersion\":\"1.0.0\",\"Copyright\":\"(c) Anam Navied. All rights reserved.\",\"PrivateData\":{\"PSData\":{\"Tags\":[\"Test\",\"CommandsAndResource\",\"Tag2\"]}},\"RequiredModules\":[],\"Description\":\"This is a test module, for PSGallery team internal testing. Do not take a dependency on this package. This version contains tags for the package.\",\"AliasesToExport\":[]}"
725-
* }
726-
* }
727-
* ]
728-
* }
729-
*/
730-
731-
var serverPkgInfo = GetMetadataProperty(foundTags, packageName, out errRecord);
709+
/*
710+
Response returned looks something like:
711+
{
712+
"schemaVersion": 2,
713+
"config": {
714+
"mediaType": "application/vnd.unknown.config.v1+json",
715+
"digest": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
716+
"size": 0
717+
},
718+
"layers": [
719+
{
720+
"mediaType": "application/vnd.oci.image.layer.nondistributable.v1.tar+gzip'",
721+
"digest": "sha256:7c55c7b66cb075628660d8249cc4866f16e34741c246a42ed97fb23ccd4ea956",
722+
"size": 3533,
723+
"annotations": {
724+
"org.opencontainers.image.title": "test_module.1.0.0.nupkg",
725+
"metadata": "{\"GUID\":\"45219bf4-10a4-4242-92d6-9bfcf79878fd\",\"FunctionsToExport\":[],\"CompanyName\":\"Anam\",\"CmdletsToExport\":[],\"VariablesToExport\":\"*\",\"Author\":\"Anam Navied\",\"ModuleVersion\":\"1.0.0\",\"Copyright\":\"(c) Anam Navied. All rights reserved.\",\"PrivateData\":{\"PSData\":{\"Tags\":[\"Test\",\"CommandsAndResource\",\"Tag2\"]}},\"RequiredModules\":[],\"Description\":\"This is a test module, for PSGallery team internal testing. Do not take a dependency on this package. This version contains tags for the package.\",\"AliasesToExport\":[]}"
726+
}
727+
}
728+
]
729+
}
730+
*/
731+
732+
ContainerRegistryInfo serverPkgInfo = GetMetadataProperty(foundTags, packageName, out errRecord);
732733
if (errRecord != null)
733734
{
734735
return requiredVersionResponse;
@@ -738,8 +739,9 @@ internal Hashtable GetContainerRegistryMetadata(string packageName, string exact
738739
{
739740
using (JsonDocument metadataJSONDoc = JsonDocument.Parse(serverPkgInfo.Metadata))
740741
{
741-
string pkgVersionString = String.Empty;
742+
string pkgVersionString = String.Empty;
742743
JsonElement rootDom = metadataJSONDoc.RootElement;
744+
743745
if (rootDom.TryGetProperty("ModuleVersion", out JsonElement pkgVersionElement))
744746
{
745747
// module metadata will have "ModuleVersion" property
@@ -831,7 +833,7 @@ internal ContainerRegistryInfo GetMetadataProperty(JObject foundTags, string pac
831833
errRecord = null;
832834
ContainerRegistryInfo serverPkgInfo = null;
833835

834-
var layers = foundTags["layers"];
836+
JToken layers = foundTags["layers"];
835837
if (layers == null || layers[0] == null)
836838
{
837839
errRecord = new ErrorRecord(
@@ -843,7 +845,7 @@ internal ContainerRegistryInfo GetMetadataProperty(JObject foundTags, string pac
843845
return serverPkgInfo;
844846
}
845847

846-
var annotations = layers[0]["annotations"];
848+
JToken annotations = layers[0]["annotations"];
847849
if (annotations == null)
848850
{
849851
errRecord = new ErrorRecord(
@@ -856,7 +858,7 @@ internal ContainerRegistryInfo GetMetadataProperty(JObject foundTags, string pac
856858
}
857859

858860
// Check for package name
859-
var pkgTitleJToken = annotations["org.opencontainers.image.title"];
861+
JToken pkgTitleJToken = annotations["org.opencontainers.image.title"];
860862
if (pkgTitleJToken == null)
861863
{
862864
errRecord = new ErrorRecord(
@@ -881,7 +883,7 @@ internal ContainerRegistryInfo GetMetadataProperty(JObject foundTags, string pac
881883
}
882884

883885
// Check for package metadata
884-
var pkgMetadataJToken = annotations["metadata"];
886+
JToken pkgMetadataJToken = annotations["metadata"];
885887
if (pkgMetadataJToken == null)
886888
{
887889
errRecord = new ErrorRecord(
@@ -893,10 +895,10 @@ internal ContainerRegistryInfo GetMetadataProperty(JObject foundTags, string pac
893895
return serverPkgInfo;
894896
}
895897

896-
var metadata = pkgMetadataJToken.ToString();
898+
string metadata = pkgMetadataJToken.ToString();
897899

898900
// Check for package artifact type
899-
var resourceTypeJToken = annotations["resourceType"];
901+
JToken resourceTypeJToken = annotations["resourceType"];
900902
var resourceType = resourceTypeJToken != null ? resourceTypeJToken.ToString() : "None";
901903

902904
return new ContainerRegistryInfo(metadataPkgName, metadata, resourceType);

src/code/PSResourceInfo.cs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1639,10 +1639,10 @@ internal static Dependency[] ParseHttpDependencies(string dependencyString)
16391639
internal static List<Dependency> ParseContainerRegistryDependencies(JsonElement requiredModulesElement, out string errorMsg)
16401640
{
16411641
errorMsg = string.Empty;
1642-
List<Dependency> pkgDeps = new List<Dependency>();
1642+
List<Dependency> pkgDeps = new();
16431643
if (requiredModulesElement.ValueKind == JsonValueKind.Array)
16441644
{
1645-
foreach (var dependency in requiredModulesElement.EnumerateArray())
1645+
foreach (JsonElement dependency in requiredModulesElement.EnumerateArray())
16461646
{
16471647
if (dependency.ValueKind == JsonValueKind.String)
16481648
{
@@ -1669,15 +1669,16 @@ internal static List<Dependency> ParseContainerRegistryDependencies(JsonElement
16691669
}
16701670

16711671
depVersionRange = new VersionRange(
1672-
minVersion: depNuGetVersion,
1673-
includeMinVersion: true);
1672+
minVersion: depNuGetVersion,
1673+
includeMinVersion: true
1674+
);
16741675
}
16751676
else if (dependency.TryGetProperty("RequiredVersion", out JsonElement depRequiredVersionElement))
16761677
{
16771678
// New-ScriptFileInfo will add "RequiredVersion" value as "null" if nothing is explicitly passed in,
16781679
// Which gets translated to an empty string.
16791680
// In this case, we just want the VersionRange to be VersionRange.All
1680-
if (!string.Equals(depModuleVersionElement.ToString(), string.Empty))
1681+
if (!string.Equals(depRequiredVersionElement.ToString(), string.Empty))
16811682
{
16821683
if (!NuGetVersion.TryParse(depRequiredVersionElement.ToString(), out NuGetVersion depNuGetVersion))
16831684
{
@@ -1686,10 +1687,11 @@ internal static List<Dependency> ParseContainerRegistryDependencies(JsonElement
16861687
}
16871688

16881689
depVersionRange = new VersionRange(
1689-
minVersion: depNuGetVersion,
1690-
includeMinVersion: true,
1691-
maxVersion: depNuGetVersion,
1692-
includeMaxVersion: true);
1690+
minVersion: depNuGetVersion,
1691+
includeMinVersion: true,
1692+
maxVersion: depNuGetVersion,
1693+
includeMaxVersion: true
1694+
);
16931695
}
16941696
}
16951697

test/FindPSResourceTests/FindPSResourceContainerRegistryServer.Tests.ps1

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Import-Module $modPath -Force -Verbose
66

77
Describe 'Test HTTP Find-PSResource for ACR Server Protocol' -tags 'CI' {
88

9-
BeforeAll{
9+
BeforeAll {
1010
$testModuleName = "test-module"
1111
$testModuleWith2DigitVersion = "test-2DigitPkg"
1212
$testModuleParentName = "test_parent_mod"
@@ -19,13 +19,11 @@ Describe 'Test HTTP Find-PSResource for ACR Server Protocol' -tags 'CI' {
1919

2020
$usingAzAuth = $env:USINGAZAUTH -eq 'true'
2121

22-
if ($usingAzAuth)
23-
{
22+
if ($usingAzAuth) {
2423
Write-Verbose -Verbose "Using Az module for authentication"
2524
Register-PSResourceRepository -Name $ACRRepoName -ApiVersion 'ContainerRegistry' -Uri $ACRRepoUri -Verbose
2625
}
27-
else
28-
{
26+
else {
2927
$psCredInfo = New-Object Microsoft.PowerShell.PSResourceGet.UtilClasses.PSCredentialInfo ("SecretStore", "$env:TENANTID")
3028
Register-PSResourceRepository -Name $ACRRepoName -ApiVersion 'ContainerRegistry' -Uri $ACRRepoUri -CredentialInfo $psCredInfo -Verbose
3129
}
@@ -51,18 +49,18 @@ Describe 'Test HTTP Find-PSResource for ACR Server Protocol' -tags 'CI' {
5149
$res | Should -BeNullOrEmpty
5250
}
5351

54-
$testCases2 = @{Version="[5.0.0.0]"; ExpectedVersions=@("5.0.0"); Reason="validate version, exact match"},
55-
@{Version="5.0.0.0"; ExpectedVersions=@("5.0.0"); Reason="validate version, exact match without bracket syntax"},
56-
@{Version="[1.0.0.0, 5.0.0.0]"; ExpectedVersions=@("1.0.0", "3.0.0", "5.0.0"); Reason="validate version, exact range inclusive"},
57-
@{Version="(1.0.0.0, 5.0.0.0)"; ExpectedVersions=@("3.0.0"); Reason="validate version, exact range exclusive"},
58-
@{Version="(1.0.0.0,)"; ExpectedVersions=@("3.0.0", "5.0.0"); Reason="validate version, minimum version exclusive"},
59-
@{Version="[1.0.0.0,)"; ExpectedVersions=@("1.0.0", "3.0.0", "5.0.0"); Reason="validate version, minimum version inclusive"},
60-
@{Version="(,3.0.0.0)"; ExpectedVersions=@("1.0.0"); Reason="validate version, maximum version exclusive"},
61-
@{Version="(,3.0.0.0]"; ExpectedVersions=@("1.0.0", "3.0.0"); Reason="validate version, maximum version inclusive"},
62-
@{Version="[1.0.0.0, 5.0.0.0)"; ExpectedVersions=@("1.0.0", "3.0.0"); Reason="validate version, mixed inclusive minimum and exclusive maximum version"}
63-
@{Version="(1.0.0.0, 5.0.0.0]"; ExpectedVersions=@("3.0.0", "5.0.0"); Reason="validate version, mixed exclusive minimum and inclusive maximum version"}
52+
$testCases2 = @{Version = "[5.0.0.0]"; ExpectedVersions = @("5.0.0"); Reason = "validate version, exact match" },
53+
@{Version = "5.0.0.0"; ExpectedVersions = @("5.0.0"); Reason = "validate version, exact match without bracket syntax" },
54+
@{Version = "[1.0.0.0, 5.0.0.0]"; ExpectedVersions = @("1.0.0", "3.0.0", "5.0.0"); Reason = "validate version, exact range inclusive" },
55+
@{Version = "(1.0.0.0, 5.0.0.0)"; ExpectedVersions = @("3.0.0"); Reason = "validate version, exact range exclusive" },
56+
@{Version = "(1.0.0.0,)"; ExpectedVersions = @("3.0.0", "5.0.0"); Reason = "validate version, minimum version exclusive" },
57+
@{Version = "[1.0.0.0,)"; ExpectedVersions = @("1.0.0", "3.0.0", "5.0.0"); Reason = "validate version, minimum version inclusive" },
58+
@{Version = "(,3.0.0.0)"; ExpectedVersions = @("1.0.0"); Reason = "validate version, maximum version exclusive" },
59+
@{Version = "(,3.0.0.0]"; ExpectedVersions = @("1.0.0", "3.0.0"); Reason = "validate version, maximum version inclusive" },
60+
@{Version = "[1.0.0.0, 5.0.0.0)"; ExpectedVersions = @("1.0.0", "3.0.0"); Reason = "validate version, mixed inclusive minimum and exclusive maximum version" }
61+
@{Version = "(1.0.0.0, 5.0.0.0]"; ExpectedVersions = @("3.0.0", "5.0.0"); Reason = "validate version, mixed exclusive minimum and inclusive maximum version" }
6462

65-
It "Find resource when given Name to <Reason> <Version>" -TestCases $testCases2{
63+
It "Find resource when given Name to <Reason> <Version>" -TestCases $testCases2 {
6664
# FindVersionGlobbing()
6765
param($Version, $ExpectedVersions)
6866
$res = Find-PSResource -Name $testModuleName -Version $Version -Repository $ACRRepoName
@@ -311,12 +309,23 @@ Describe 'Test Find-PSResource for MAR Repository' -tags 'CI' {
311309
$res | Should -Not -BeNullOrEmpty
312310
$res.Count | Should -BeGreaterThan 1
313311
}
312+
313+
It "Should find version range for Az dependencies" {
314+
# Target known version to know the output from the API won't change
315+
$res = Find-PSResource -Repository 'MAR' -Name 'Az' -Version '14.4.0'
316+
317+
# Version defined by "ModuleVersion"
318+
$res.Dependencies.Where{$_.'Name' -eq 'Az.Accounts'}.'VersionRange'.ToString() | Should -Be '[5.3.0, )'
319+
320+
# Version defined by "RequiredVersion"
321+
$res.Dependencies.Where{$_.'Name' -eq 'Az.Resources'}.'VersionRange'.ToString() | Should -Be '[8.1.0, 8.1.0]'
322+
}
314323
}
315324

316-
# Skip this test fo
325+
# Skip this test for Windows PowerShell
317326
Describe 'Test Find-PSResource for unauthenticated ACR repository' -tags 'CI' {
318327
BeforeAll {
319-
$skipOnWinPS = $PSVersionTable.PSVersion.Major -eq 5
328+
$skipOnWinPS = $PSVersionTable.PSVersion.Major -eq 5
320329

321330
if (-not $skipOnWinPS) {
322331
Register-PSResourceRepository -Name "Unauthenticated" -Uri "https://psresourcegetnoauth.azurecr.io/" -ApiVersion "ContainerRegistry"

0 commit comments

Comments
 (0)