diff --git a/src/code/PublishPSResource.cs b/src/code/PublishPSResource.cs index 524e86ae1..e734cf3de 100644 --- a/src/code/PublishPSResource.cs +++ b/src/code/PublishPSResource.cs @@ -17,13 +17,12 @@ namespace Microsoft.PowerShell.PSResourceGet.Cmdlets "PSResource", SupportsShouldProcess = true)] [Alias("pbres")] - public sealed class PublishPSResource : PSCmdlet, IDynamicParameters + public sealed class PublishPSResource : PSCmdlet { #region Parameters private const string PathParameterSet = "PathParameterSet"; private const string NupkgPathParameterSet = "NupkgPathParameterSet"; - private ContainerRegistryDynamicParameters _pkgPrefix; /// /// Specifies the API key that you want to use to publish a module to the online gallery. @@ -117,20 +116,12 @@ public PSCredential ProxyCredential { [ValidateNotNullOrEmpty] public string NupkgPath { get; set; } - #endregion - - #region DynamicParameters - public object GetDynamicParameters() - { - PSRepositoryInfo repository = RepositorySettings.Read(new[] { Repository }, out string[] _).FirstOrDefault(); - if (repository is not null && repository.ApiVersion == PSRepositoryInfo.APIVersion.ContainerRegistry) - { - _pkgPrefix = new ContainerRegistryDynamicParameters(); - return _pkgPrefix; - } - - return null; - } + /// + /// Prefix for module name which only applies to repositories of type 'ContainerRegistry' + /// + [Parameter] + [ValidateNotNullOrEmpty] + public string ModulePrefix { get; set; } #endregion @@ -151,16 +142,41 @@ protected override void BeginProcessing() _networkCredential = Credential != null ? new NetworkCredential(Credential.UserName, Credential.Password) : null; + // Create the repository store file (PSResourceRepository.xml) if it does not already exist + // This is to create a better experience for those who have just installed v3 and want to get up and running quickly + RepositorySettings.CheckRepositoryStore(); + + if (MyInvocation.BoundParameters.ContainsKey(nameof(ModulePrefix))) + { + if (MyInvocation.BoundParameters.ContainsKey(nameof(Repository))) + { + // at this point it is ensured PSResourceRepository.xml file is created + PSRepositoryInfo repository = RepositorySettings.Read(new[] { Repository }, out string[] _).FirstOrDefault(); + if (repository is null || repository.ApiVersion != PSRepositoryInfo.APIVersion.ContainerRegistry) + { + ThrowTerminatingError(new ErrorRecord( + new PSInvalidOperationException("ModulePrefix parameter can only be provided for a registered repository of type 'ContainerRegistry'"), + "ModulePrefixParameterIncorrectlyProvided", + ErrorCategory.InvalidOperation, + this)); + } + } + else + { + ThrowTerminatingError(new ErrorRecord( + new PSInvalidOperationException("ModulePrefix parameter can only be provided with the Repository parameter."), + "ModulePrefixParameterProvidedWithoutRepositoryParameter", + ErrorCategory.InvalidOperation, + this)); + } + } + if (!string.IsNullOrEmpty(NupkgPath)) { _isNupkgPathSpecified = true; Path = NupkgPath; } - // Create a respository story (the PSResourceRepository.xml file) if it does not already exist - // This is to create a better experience for those who have just installed v3 and want to get up and running quickly - RepositorySettings.CheckRepositoryStore(); - _publishHelper = new PublishHelper( this, Credential, @@ -186,18 +202,10 @@ protected override void EndProcessing() return; } - string modulePrefix = _pkgPrefix?.ModulePrefix; - - _publishHelper.PushResource(Repository, modulePrefix, SkipDependenciesCheck, _networkCredential); + _publishHelper.PushResource(Repository, ModulePrefix, SkipDependenciesCheck, _networkCredential); } #endregion } - - public class ContainerRegistryDynamicParameters - { - [Parameter] - public string ModulePrefix { get; set; } - } } diff --git a/test/PublishPSResourceTests/PublishPSResource.Tests.ps1 b/test/PublishPSResourceTests/PublishPSResource.Tests.ps1 index 84e941dfa..46844987d 100644 --- a/test/PublishPSResourceTests/PublishPSResource.Tests.ps1 +++ b/test/PublishPSResourceTests/PublishPSResource.Tests.ps1 @@ -99,6 +99,8 @@ Describe "Test Publish-PSResource" -tags 'CI' { # Create test module with missing required module CreateTestModule -Path $TestDrive -ModuleName 'ModuleWithMissingRequiredModule' + + $script:PSGalleryName = 'PSGallery' } AfterAll { Get-RevertPSResourceRepositoryFile @@ -149,6 +151,44 @@ Describe "Test Publish-PSResource" -tags 'CI' { (Get-ChildItem $script:repositoryPath).FullName | Should -Be $expectedPath } + It "Publish should create PSResourceRepository.xml file if its not there" { + # Remove the PSResourceRepository.xml file + $powerShellGetPath = Join-Path -Path ([Environment]::GetFolderPath([System.Environment+SpecialFolder]::LocalApplicationData)) -ChildPath "PSResourceGet" + $originalXmlFilePath = Join-Path -Path $powerShellGetPath -ChildPath "PSResourceRepository.xml" #this is the temporary PSResourceRepository.xml file created in the 'BeforeAll' section of this test file + + $tempXmlFilePath = Join-Path -Path $powerShellGetPath -ChildPath "tempfortest.xml" + + if (Test-Path -Path $originalXmlFilePath) { + Copy-Item -Path $originalXmlFilePath -Destination $tempXmlFilePath + Remove-Item -Path $originalXmlFilePath -Force -ErrorAction Ignore + } + + # Attempt to publish. + # Publish-PSResource should create PSResourceRepository.xml file if not present. It will register the 'PSGallery' repository as a default, so this test will still fail + # But we can ensure the PSResourceRepository.xml file is created. + $version = "1.0.0" + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" + + Publish-PSResource -Path $script:PublishModuleBase -Repository $testRepository2 -ErrorVariable err -ErrorAction SilentlyContinue + $err[0].FullyQualifiedErrorId | Should -Be "RepositoryNotRegistered,Microsoft.PowerShell.PSResourceGet.Cmdlets.PublishPSResource" + + $registeredRepos = Get-PSResourceRepository + $registeredRepos.Count | Should -Be 1 + $registeredRepos[0].Name | Should -Be $script:PSGalleryName + + # Cleanup + # Remove the new PSResourceRepository.xml file created by the Publish-PSResource command and put back the original created in the 'BeforeAll' section of this test file + if (Test-Path -Path $tempXmlFilePath) { + Copy-Item -Path $tempXmlFilePath -Destination $originalXmlFilePath -Force -Verbose + Remove-Item -Path $tempXmlFilePath -Force -ErrorAction Ignore + } + + # Verify old repositories are restored + $originalRegisteredRepo = Get-PSResourceRepository -Name $testRepository2 -ErrorVariable err2 -ErrorAction SilentlyContinue + $err2.Count | Should -Be 0 + $originalRegisteredRepo.Name | Should -Be $testRepository2 + } + #region Local Source Path It "Publish a module with -Path and -Repository" { $version = "1.0.0" diff --git a/test/PublishPSResourceTests/PublishPSResourceContainerRegistryServer.Tests.ps1 b/test/PublishPSResourceTests/PublishPSResourceContainerRegistryServer.Tests.ps1 index af57385a1..deac2f101 100644 --- a/test/PublishPSResourceTests/PublishPSResourceContainerRegistryServer.Tests.ps1 +++ b/test/PublishPSResourceTests/PublishPSResourceContainerRegistryServer.Tests.ps1 @@ -100,6 +100,8 @@ Describe "Test Publish-PSResource" -tags 'CI' { # Path to specifically to that invalid test nupkgs folder $script:testNupkgsFolderPath = Join-Path $script:testFilesFolderPath -ChildPath "testNupkgs" + + $script:PSGalleryName = "PSGallery" } AfterEach { if(!(Test-Path $script:PublishModuleBase)) @@ -515,6 +517,27 @@ Describe "Test Publish-PSResource" -tags 'CI' { $results[0].Version | Should -Be $version } + It "not Publish a resource when ModulePrefix is given for a Repository that is not of type ContainerRegistry" + { + $version = "1.0.0" + $modulePrefix = "unlisted" + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" + + Publish-PSResource -Path $script:PublishModuleBase -Repository $script:PSGalleryName -ModulePrefix $modulePrefix -ErrorVariable err -ErrorAction SilentlyContinue + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "ModulePrefixParameterIncorrectlyProvided,Microsoft.PowerShell.PSResourceGet.Cmdlets.PublishPSResource" + } + + It "not Publish a resource when ModulePrefix is provided without Repository parameter" { + $version = "1.0.0" + $modulePrefix = "unlisted" + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") -ModuleVersion $version -Description "$script:PublishModuleName module" + + Publish-PSResource -Path $script:PublishModuleBase -ModulePrefix $modulePrefix -ErrorVariable err -ErrorAction SilentlyContinue + $err.Count | Should -Not -Be 0 + $err[0].FullyQualifiedErrorId | Should -BeExactly "ModulePrefixParameterProvidedWithoutRepositoryParameter,Microsoft.PowerShell.PSResourceGet.Cmdlets.PublishPSResource" + } + It "Publish a package given NupkgPath to a package with .psd1" { $packageName = "temp-testmodule-nupkgpath" $version = "1.0.0.0"