PowerShell / PSResourceGet

PSResourceGet is the package manager for PowerShell
https://www.powershellgallery.com/packages/Microsoft.PowerShell.PSResourceGet
MIT License
475 stars 90 forks source link

Find-PSResource requires 'tags' in server response even when not using -Tag #1621

Closed evelyn-bi closed 2 months ago

evelyn-bi commented 3 months ago

Prerequisites

Steps to reproduce

We use a Gitea NuGet package repository using the NuGet V3 API protocol. Apparently Gitea is not returning tags when it gives search results.

Using the new PSResourceGet's Find-PSResource using just -Name or both -Name and -Version I get an error saying 'tags' must be in the response. This is with version 1.0.3 Microsoft.PowerShell.PSResourceGet. Note that using the old PowerShellGet Register-PSRepository to register this same Gitea repository works when searching for a PowerShell NuGet package, e.g., Find-Script -Repository $repo -Name $script -RequiredVersion 1.0.0.

PS> Find-PSResource -repository $repo -Name $scriptName -Version 1.0.0
Find-PSResource: Response does not contain 'tags' element for search with name '$scriptName' and version '1.0.0' in repository '$repo'.
PS> Find-PSResource -repository $repo -Name $scriptName
Find-PSResource: Response does not contain 'tags' element for search with Name '$scriptName' in '$repo'.

According to https://learn.microsoft.com/en-us/nuget/api/search-query-service-resource#search-result, only id, version, versions, and packageTypes are required, 'tags' is optional.

Possible Fix

The V3ServerAPICalls.cs maybe just has a bug in both FindVersionHelper at https://github.com/PowerShell/PSResourceGet/blob/ce1d459e28c07c2cf35cdf75b1244695e0a3d70e/src/code/V3ServerAPICalls.cs#L564, and FindNameHelper at https://github.com/PowerShell/PSResourceGet/blob/ce1d459e28c07c2cf35cdf75b1244695e0a3d70e/src/code/V3ServerAPICalls.cs#L467, both of these have callers with tags: Utils.EmptyStrArray but the FindHelper methods always look for the 'tags' element in the server response.

From a quick look it seems IsRequiredTagSatisfied() will work with empty tags, so maybe the only code that needs fixed are the two copies of the below code (FindName and FindVersion helpers) to only execute if the string[] tags parameter isn't empty:

if (!rootDom.TryGetProperty(tagsName, out JsonElement tagsItem))
{
   // broken
}

Likely just needs to be:

if (!rootDom.TryGetProperty(tagsName, out JsonElement tagsItem) && tags.Length != 0)
{
   // fixed when I build the module myself
}

I tested building the module using the above code and it seems to work fine for me, Find-PSResource now finds the script on my Gitea server despite the server not returning 'tags' in the response. Main thing is to ensure && tags.Length != 0 is second because out JsonElement tagsItem has to run to prevent an "Use of unassigned local variable 'tagsItem'" error during build.

Expected behavior

PS> Find-PSResource -repository $repo -Name $scriptName -Version 1.0.0
{should return the matching NuGet package even when the server response has no 'tags' element}

PS> Find-PSResource -repository $repo -Name $scriptName
{should return the matching NuGet package even when the server response has no 'tags' element}

Actual behavior

PS> Find-PSResource -repository $repo -Name $scriptName -Version 1.0.0
Find-PSResource: Response does not contain 'tags' element for search with name '$scriptName' and version '1.0.0' in repository '$repo'.
PS> Find-PSResource -repository $repo -Name $scriptName
Find-PSResource: Response does not contain 'tags' element for search with Name '$scriptName' in '$repo'.

Error details

Exception             :
    Type    : Microsoft.PowerShell.PSResourceGet.UtilClasses.InvalidOrEmptyResponse
    Message : Response does not contain 'tags' element for search with Name '$script' in '$repo'.
    HResult : -2146233088
TargetObject          : Microsoft.PowerShell.PSResourceGet.Cmdlets.V3ServerAPICalls
CategoryInfo          : InvalidResult: (Microsoft.PowerShel…ts.V3ServerAPICalls:V3ServerAPICalls) [Find-PSResource],
InvalidOrEmptyResponse
FullyQualifiedErrorId : FindNameFailure,Microsoft.PowerShell.PSResourceGet.Cmdlets.FindPSResource
InvocationInfo        :
    MyCommand        : Find-PSResource
    ScriptLineNumber : 1
    OffsetInLine     : 1
    HistoryId        : 31
    Line             : Find-PSResource -repository $repo -Name $script
    Statement        : Find-PSResource -repository $repo -Name $script
    PositionMessage  : At line:1 char:1
                       + Find-PSResource -repository $repo -Name $script
                       + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    InvocationName   : Find-PSResource
    CommandOrigin    : Internal
ScriptStackTrace      : at <ScriptBlock>, <No file>: line 1
PipelineIterationInfo :

Exception             :
    Type    : Microsoft.PowerShell.PSResourceGet.UtilClasses.InvalidOrEmptyResponse
    Message : Response does not contain 'tags' element for search with name '$script' and version '1.0.0' in
repository '$repo'.
    HResult : -2146233088
TargetObject          : Microsoft.PowerShell.PSResourceGet.Cmdlets.V3ServerAPICalls
CategoryInfo          : InvalidResult: (Microsoft.PowerShel…ts.V3ServerAPICalls:V3ServerAPICalls) [Find-PSResource],
InvalidOrEmptyResponse
FullyQualifiedErrorId : FindVersionFailure,Microsoft.PowerShell.PSResourceGet.Cmdlets.FindPSResource
InvocationInfo        :
    MyCommand        : Find-PSResource
    ScriptLineNumber : 1
    OffsetInLine     : 1
    HistoryId        : 33
    Line             : Find-PSResource -repository $repo -Name $script -Version 1.0.0
    Statement        : Find-PSResource -repository $repo -Name $script -Version 1.0.0
    PositionMessage  : At line:1 char:1
                       + Find-PSResource -repository $repo -Name $script -Versio …
                       + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    InvocationName   : Find-PSResource
    CommandOrigin    : Internal
ScriptStackTrace      : at <ScriptBlock>, <No file>: line 1
PipelineIterationInfo :

Environment data

>PS Get-Module Microsoft.PowerShell.PSResourceGet; $PSVersionTable

ModuleType Version    PreRelease Name                                ExportedCommands
---------- -------    ---------- ----                                ----------------
Binary     1.0.3                 Microsoft.PowerShell.PSResourceGet  {Find-PSResource, Get-InstalledPSResource, Get-PS…

Key   : PSVersion
Value : 7.4.1
Name  : PSVersion

Key   : PSEdition
Value : Core
Name  : PSEdition

Key   : GitCommitId
Value : 7.4.1
Name  : GitCommitId

Key   : OS
Value : Microsoft Windows 10.0.19044
Name  : OS

Key   : Platform
Value : Win32NT
Name  : Platform

Key   : PSCompatibleVersions
Value : {1.0, 2.0, 3.0, 4.0…}
Name  : PSCompatibleVersions

Key   : PSRemotingProtocolVersion
Value : 2.3
Name  : PSRemotingProtocolVersion

Key   : SerializationVersion
Value : 1.1.0.1
Name  : SerializationVersion

Key   : WSManStackVersion
Value : 3.0
Name  : WSManStackVersion

Visuals

No response

SydneyhSmith commented 3 months ago

Thanks @evelyn-bi , feel free to open a PR with this fix-- thanks

evelyn-bi commented 3 months ago

Thanks @evelyn-bi , feel free to open a PR with this fix-- thanks

@SydneyhSmith I haven't had a chance to figure out the tests in this project, if there are simulated server responses it should just be a matter of duplicating some existing test but removing the 'tags' element from the server response to make sure the old code fails the test and the new code passes it. I don't know when I will have time to figure that stuff out, do you think this pull request is worth it without the test?

SydneyhSmith commented 3 months ago

@evelyn-bi yeah feel free to open without the tests