Skip to content

Commit

Permalink
Bugfix - Correctly match package names from local repos (PowerShell#1731
Browse files Browse the repository at this point in the history
)

* Fix pattern matching code to match specific pkgName.version.nupkg not packageName* to avoid unwanted wildcard clashes

* remove unused code

* remove unused code some more

* use Regex instead of WildcardPattern for FindVersion() too

* add tests

* remove comment

* add ErrorVariable reference

* addres PR feedback about comments and debug message

* add comment
  • Loading branch information
anamnavi authored Oct 22, 2024
1 parent b8a3013 commit 5bbc687
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 29 deletions.
91 changes: 62 additions & 29 deletions src/code/LocalServerApiCalls.cs
Original file line number Diff line number Diff line change
Expand Up @@ -255,32 +255,48 @@ private FindResults FindNameHelper(string packageName, string[] tags, bool inclu
FindResults findResponse = new FindResults();
errRecord = null;

WildcardPattern pkgNamePattern = new WildcardPattern($"{packageName}.*", WildcardOptions.IgnoreCase);
NuGetVersion latestVersion = new NuGetVersion("0.0.0.0");
String latestVersionPath = String.Empty;
string actualPkgName = packageName;

// this regex pattern matches packageName followed by a version (4 digit or 3 with prerelease word)
string regexPattern = $"{packageName}" + @".\d+\.\d+\.\d+(?:-\w+|.\d)*.nupkg";
Regex rx = new Regex(regexPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
_cmdletPassedIn.WriteDebug($"package file name pattern to be searched for is: {regexPattern}");

foreach (string path in Directory.GetFiles(Repository.Uri.LocalPath))
{
string packageFullName = Path.GetFileName(path);
MatchCollection matches = rx.Matches(packageFullName);
if (matches.Count == 0)
{
continue;
}

if (!String.IsNullOrEmpty(packageFullName) && pkgNamePattern.IsMatch(packageFullName))
Match match = matches[0];

GroupCollection groups = match.Groups;
if (groups.Count == 0)
{
NuGetVersion nugetVersion = GetInfoFromFileName(packageFullName: packageFullName, packageName: packageName, actualName: out actualPkgName, out errRecord);
_cmdletPassedIn.WriteDebug($"Version parsed as '{nugetVersion}'");
continue;
}

if (errRecord != null)
{
return findResponse;
}
Capture group = groups[0];

if ((!nugetVersion.IsPrerelease || includePrerelease) && (nugetVersion > latestVersion))
NuGetVersion nugetVersion = GetInfoFromFileName(packageFullName: packageFullName, packageName: packageName, actualName: out actualPkgName, out errRecord);
_cmdletPassedIn.WriteDebug($"Version parsed as '{nugetVersion}'");

if (errRecord != null)
{
return findResponse;
}

if ((!nugetVersion.IsPrerelease || includePrerelease) && (nugetVersion > latestVersion))
{
if (nugetVersion > latestVersion)
{
if (nugetVersion > latestVersion)
{
latestVersion = nugetVersion;
latestVersionPath = path;
}
latestVersion = nugetVersion;
latestVersionPath = path;
}
}
}
Expand Down Expand Up @@ -371,29 +387,46 @@ private FindResults FindVersionHelper(string packageName, string version, string
return findResponse;
}

WildcardPattern pkgNamePattern = new WildcardPattern($"{packageName}.*", WildcardOptions.IgnoreCase);
// this regex pattern matches packageName followed by the requested version
string regexPattern = $"{packageName}.{requiredVersion.ToNormalizedString()}" + @".nupkg";
Regex rx = new Regex(regexPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
_cmdletPassedIn.WriteDebug($"pattern is: {regexPattern}");
string pkgPath = String.Empty;
string actualPkgName = String.Empty;

foreach (string path in Directory.GetFiles(Repository.Uri.LocalPath))
{
string packageFullName = Path.GetFileName(path);
if (!String.IsNullOrEmpty(packageFullName) && pkgNamePattern.IsMatch(packageFullName))
MatchCollection matches = rx.Matches(packageFullName);
if (matches.Count == 0)
{
NuGetVersion nugetVersion = GetInfoFromFileName(packageFullName: packageFullName, packageName: packageName, actualName: out actualPkgName, out errRecord);
_cmdletPassedIn.WriteDebug($"'{packageName}' version parsed as '{nugetVersion}'");
continue;
}

if (errRecord != null)
{
return findResponse;
}
Match match = matches[0];

if (nugetVersion == requiredVersion)
{
_cmdletPassedIn.WriteDebug("Found matching version");
string pkgFullName = $"{actualPkgName}.{nugetVersion.ToString()}.nupkg";
pkgPath = Path.Combine(Repository.Uri.LocalPath, pkgFullName);
break;
}
GroupCollection groups = match.Groups;
if (groups.Count == 0)
{
continue;
}

Capture group = groups[0];

NuGetVersion nugetVersion = GetInfoFromFileName(packageFullName: packageFullName, packageName: packageName, actualName: out actualPkgName, out errRecord);
_cmdletPassedIn.WriteDebug($"Version parsed as '{nugetVersion}'");

if (errRecord != null)
{
return findResponse;
}

if (nugetVersion == requiredVersion)
{
_cmdletPassedIn.WriteDebug("Found matching version");
string pkgFullName = $"{actualPkgName}.{nugetVersion.ToString()}.nupkg";
pkgPath = Path.Combine(Repository.Uri.LocalPath, pkgFullName);
break;
}
}

Expand Down
32 changes: 32 additions & 0 deletions test/FindPSResourceTests/FindPSResourceLocal.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Describe 'Test Find-PSResource for local repositories' -tags 'CI' {
$localUNCRepo = 'psgettestlocal3'
$testModuleName = "test_local_mod"
$testModuleName2 = "test_local_mod2"
$similarTestModuleName = "test_local_mod.similar"
$commandName = "cmd1"
$dscResourceName = "dsc1"
$prereleaseLabel = ""
Expand All @@ -31,6 +32,9 @@ Describe 'Test Find-PSResource for local repositories' -tags 'CI' {

New-TestModule -moduleName $testModuleName2 -repoName $localRepo -packageVersion "5.0.0" -prereleaseLabel "" -tags $tagsEscaped
New-TestModule -moduleName $testModuleName2 -repoName $localRepo -packageVersion "5.2.5" -prereleaseLabel $prereleaseLabel -tags $tagsEscaped

New-TestModule -moduleName $similarTestModuleName -repoName $localRepo -packageVersion "4.0.0" -prereleaseLabel "" -tags $tagsEscaped
New-TestModule -moduleName $similarTestModuleName -repoName $localRepo -packageVersion "5.0.0" -prereleaseLabel "" -tags $tagsEscaped
}

AfterAll {
Expand Down Expand Up @@ -74,13 +78,25 @@ Describe 'Test Find-PSResource for local repositories' -tags 'CI' {
}

It "should not find resource given nonexistant Name" {
# FindName()
$res = Find-PSResource -Name NonExistantModule -Repository $localRepo -ErrorVariable err -ErrorAction SilentlyContinue
$res | Should -BeNullOrEmpty
$err.Count | Should -Not -Be 0
$err[0].FullyQualifiedErrorId | Should -BeExactly "PackageNotFound,Microsoft.PowerShell.PSResourceGet.Cmdlets.FindPSResource"
$res | Should -BeNullOrEmpty
}

It "find resource given specific Name when another package with similar name (with period) exists" {
# FindName()
$res = Find-PSResource -Name $testModuleName -Repository $localRepo
$res.Name | Should -Be $testModuleName
$res.Version | Should -Be "5.0.0"

$res = Find-PSResource -Name $similarTestModuleName -Repository $localRepo
$res.Name | Should -Be $similarTestModuleName
$res.Version | Should -Be "5.0.0"
}

It "find resource(s) given wildcard Name" {
# FindNameGlobbing
$res = Find-PSResource -Name "test_local_*" -Repository $localRepo
Expand Down Expand Up @@ -129,6 +145,22 @@ Describe 'Test Find-PSResource for local repositories' -tags 'CI' {
$resPrerelease.Prerelease | Should -Be "alpha001"
}

It "find resource given specific Name when another package with similar name (with period) exists" {
# FindVersion()
# Package $testModuleName version 4.0.0 does not exist
# previously if Find-PSResource -Version against local repo did not find that package's version it kept looking at
# similar named packages and would fault. This test is to ensure only the specified package and its version is checked
$res = Find-PSResource -Name $testModuleName -Version "4.0.0" -Repository $localRepo -ErrorVariable err -ErrorAction SilentlyContinue
$res | Should -BeNullOrEmpty
$err.Count | Should -Not -Be 0
$err[0].FullyQualifiedErrorId | Should -BeExactly "PackageNotFound,Microsoft.PowerShell.PSResourceGet.Cmdlets.FindPSResource"
$res | Should -BeNullOrEmpty

$res = Find-PSResource -Name $similarTestModuleName -Version "4.0.0" -Repository $localRepo
$res.Name | Should -Be $similarTestModuleName
$res.Version | Should -Be "4.0.0"
}

It "find resources, including Prerelease version resources, when given Prerelease parameter" {
# FindVersionGlobbing()
$resWithoutPrerelease = Find-PSResource -Name $testModuleName -Version "*" -Repository $localRepo
Expand Down

0 comments on commit 5bbc687

Please sign in to comment.