From cf7ee196805868d536ed8737e4e985935e162879 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Wed, 19 Feb 2025 11:40:36 -0800 Subject: [PATCH] Allow wildcard for MAR repository for FindAll and FindByName (#1786) --- src/code/ContainerRegistryServerAPICalls.cs | 92 ++++++++++++++++--- ...SResourceContainerRegistryServer.Tests.ps1 | 14 ++- 2 files changed, 92 insertions(+), 14 deletions(-) diff --git a/src/code/ContainerRegistryServerAPICalls.cs b/src/code/ContainerRegistryServerAPICalls.cs index d9175c0b0..973525daa 100644 --- a/src/code/ContainerRegistryServerAPICalls.cs +++ b/src/code/ContainerRegistryServerAPICalls.cs @@ -46,6 +46,7 @@ internal class ContainerRegistryServerAPICalls : ServerApiCall const string containerRegistryFindImageVersionUrlTemplate = "https://{0}/v2/{1}/tags/list"; // 0 - registry, 1 - repo(modulename) const string containerRegistryStartUploadTemplate = "https://{0}/v2/{1}/blobs/uploads/"; // 0 - registry, 1 - packagename const string containerRegistryEndUploadTemplate = "https://{0}{1}&digest=sha256:{2}"; // 0 - registry, 1 - location, 2 - digest + const string containerRegistryRepositoryListTemplate = "https://{0}/v2/_catalog"; // 0 - registry #endregion @@ -76,13 +77,13 @@ public ContainerRegistryServerAPICalls(PSRepositoryInfo repository, PSCmdlet cmd public override FindResults FindAll(bool includePrerelease, ResourceType type, out ErrorRecord errRecord) { _cmdletPassedIn.WriteDebug("In ContainerRegistryServerAPICalls::FindAll()"); - errRecord = new ErrorRecord( - new InvalidOperationException($"Find all is not supported for the ContainerRegistry server protocol repository '{Repository.Name}'"), - "FindAllFailure", - ErrorCategory.InvalidOperation, - this); + var findResult = FindPackages("*", includePrerelease, out errRecord); + if (errRecord != null) + { + return emptyResponseResults; + } - return emptyResponseResults; + return findResult; } /// @@ -161,13 +162,13 @@ public override FindResults FindNameWithTag(string packageName, string[] tags, b public override FindResults FindNameGlobbing(string packageName, bool includePrerelease, ResourceType type, out ErrorRecord errRecord) { _cmdletPassedIn.WriteDebug("In ContainerRegistryServerAPICalls::FindNameGlobbing()"); - errRecord = new ErrorRecord( - new InvalidOperationException($"FindNameGlobbing all is not supported for the ContainerRegistry server protocol repository '{Repository.Name}'"), - "FindNameGlobbingFailure", - ErrorCategory.InvalidOperation, - this); + var findResult = FindPackages(packageName, includePrerelease, out errRecord); + if (errRecord != null) + { + return emptyResponseResults; + } - return emptyResponseResults; + return findResult; } /// @@ -591,6 +592,20 @@ internal JObject FindContainerRegistryImageTags(string packageName, string versi return GetHttpResponseJObjectUsingDefaultHeaders(findImageUrl, HttpMethod.Get, defaultHeaders, out errRecord); } + /// + /// Helper method to find all packages on container registry + /// + /// + /// + /// + internal JObject FindAllRepositories(string containerRegistryAccessToken, out ErrorRecord errRecord) + { + _cmdletPassedIn.WriteDebug("In ContainerRegistryServerAPICalls::FindAllRepositories()"); + string repositoryListUrl = string.Format(containerRegistryRepositoryListTemplate, Registry); + var defaultHeaders = GetDefaultHeaders(containerRegistryAccessToken); + return GetHttpResponseJObjectUsingDefaultHeaders(repositoryListUrl, HttpMethod.Get, defaultHeaders, out errRecord); + } + /// /// Get metadata for a package version. /// @@ -1705,12 +1720,63 @@ private string PrependMARPrefix(string packageName) // If the repostitory is MAR and its not a wildcard search, we need to prefix the package name with MAR prefix. string updatedPackageName = Repository.IsMARRepository() && packageName.Trim() != "*" - ? string.Concat(prefix, packageName) + ? packageName.StartsWith(prefix) ? packageName : string.Concat(prefix, packageName) : packageName; return updatedPackageName; } + private FindResults FindPackages(string packageName, bool includePrerelease, out ErrorRecord errRecord) + { + _cmdletPassedIn.WriteDebug("In ContainerRegistryServerAPICalls::FindPackages()"); + errRecord = null; + string containerRegistryAccessToken = GetContainerRegistryAccessToken(out errRecord); + if (errRecord != null) + { + return emptyResponseResults; + } + + var pkgResult = FindAllRepositories(containerRegistryAccessToken, out errRecord); + if (errRecord != null) + { + return emptyResponseResults; + } + + List repositoriesList = new List(); + var isMAR = Repository.IsMARRepository(); + + // Convert the list of repositories to a list of hashtables + foreach (var repository in pkgResult["repositories"].ToList()) + { + string repositoryName = repository.ToString(); + + if (isMAR && !repositoryName.StartsWith(PSRepositoryInfo.MARPrefix)) + { + continue; + } + + // This remove the 'psresource/' prefix from the repository name for comparison with wildcard. + string moduleName = repositoryName.Substring(11); + + WildcardPattern wildcardPattern = new WildcardPattern(packageName, WildcardOptions.IgnoreCase); + + if (!wildcardPattern.IsMatch(moduleName)) + { + continue; + } + + _cmdletPassedIn.WriteDebug($"Found repository: {repositoryName}"); + + repositoriesList.AddRange(FindPackagesWithVersionHelper(repositoryName, VersionType.VersionRange, versionRange: VersionRange.All, requiredVersion: null, includePrerelease, getOnlyLatest: true, out errRecord)); + if (errRecord != null) + { + return emptyResponseResults; + } + } + + return new FindResults(stringResponse: new string[] { }, hashtableResponse: repositoriesList.ToArray(), responseType: containerRegistryFindResponseType); + } + #endregion } } diff --git a/test/FindPSResourceTests/FindPSResourceContainerRegistryServer.Tests.ps1 b/test/FindPSResourceTests/FindPSResourceContainerRegistryServer.Tests.ps1 index b7ffdfb8e..3b403b24d 100644 --- a/test/FindPSResourceTests/FindPSResourceContainerRegistryServer.Tests.ps1 +++ b/test/FindPSResourceTests/FindPSResourceContainerRegistryServer.Tests.ps1 @@ -247,7 +247,7 @@ Describe 'Test Find-PSResource for MAR Repository' -tags 'CI' { It "Should find resource given specific Name, Version null" { $res = Find-PSResource -Name "Az.Accounts" -Repository "MAR" $res.Name | Should -Be "Az.Accounts" - $res.Version | Should -Be "4.0.0" + $res.Version | Should -BeGreaterThan ([Version]"4.0.0") } It "Should find resource and its dependency given specific Name and Version" { @@ -255,4 +255,16 @@ Describe 'Test Find-PSResource for MAR Repository' -tags 'CI' { $res.Dependencies.Length | Should -Be 1 $res.Dependencies[0].Name | Should -Be "Az.Accounts" } + + It "Should find resource with wildcard in Name" { + $res = Find-PSResource -Name "Az.App*" -Repository "MAR" + $res | Should -Not -BeNullOrEmpty + $res.Count | Should -BeGreaterThan 1 + } + + It "Should find all resource with wildcard in Name" { + $res = Find-PSResource -Name "*" -Repository "MAR" + $res | Should -Not -BeNullOrEmpty + $res.Count | Should -BeGreaterThan 1 + } }