From fd47e152d3f3d036531980c8bf908b6b25055ed2 Mon Sep 17 00:00:00 2001 From: Amber Erickson Date: Wed, 13 Mar 2019 11:09:56 -0700 Subject: [PATCH 01/19] **DISABLE_SECRET_SCANNING** From c00f461828e77087f0141499abe116d2dda57fb3 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Wed, 13 Mar 2019 17:37:26 -0700 Subject: [PATCH 02/19] Merge development to master (#440) --- CHANGELOG.md | 4 + SignCat.xml | 9 ++ SignConfig.xml | 23 ++++++ src/PowerShellGet/PowerShellGet.psd1 | 118 ++++++++++++++------------- 4 files changed, 97 insertions(+), 57 deletions(-) create mode 100644 SignCat.xml create mode 100644 SignConfig.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index 5cc86553..7063ff90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## 2.1.1 +- Fix DSC resource folder structure + ## 2.1.0 Breaking Change @@ -18,6 +21,7 @@ Bug Fixes New Features - New DSC resource, PSRepository (#426) (Thanks @johlju!) +- Added tests and integration of DSC resource PSModule (Thanks @johlju!) - Piping of PS respositories (#420) - utf8 support for .nuspec (#419) diff --git a/SignCat.xml b/SignCat.xml new file mode 100644 index 00000000..9b16b2d4 --- /dev/null +++ b/SignCat.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/SignConfig.xml b/SignConfig.xml new file mode 100644 index 00000000..d3d51d60 --- /dev/null +++ b/SignConfig.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/PowerShellGet/PowerShellGet.psd1 b/src/PowerShellGet/PowerShellGet.psd1 index 4c82b748..9df2d0eb 100644 --- a/src/PowerShellGet/PowerShellGet.psd1 +++ b/src/PowerShellGet/PowerShellGet.psd1 @@ -1,59 +1,63 @@ @{ -RootModule = 'PSModule.psm1' -ModuleVersion = '2.1.0' -GUID = '1d73a601-4a6c-43c5-ba3f-619b18bbb404' -Author = 'Microsoft Corporation' -CompanyName = 'Microsoft Corporation' -Copyright = '(c) Microsoft Corporation. All rights reserved.' -Description = 'PowerShell module with commands for discovering, installing, updating and publishing the PowerShell artifacts like Modules, DSC Resources, Role Capabilities and Scripts.' -PowerShellVersion = '3.0' -FormatsToProcess = 'PSGet.Format.ps1xml' -FunctionsToExport = @( - 'Find-Command', - 'Find-DSCResource', - 'Find-Module', - 'Find-RoleCapability', - 'Find-Script', - 'Get-InstalledModule', - 'Get-InstalledScript', - 'Get-PSRepository', - 'Install-Module', - 'Install-Script', - 'New-ScriptFileInfo', - 'Publish-Module', - 'Publish-Script', - 'Register-PSRepository', - 'Save-Module', - 'Save-Script', - 'Set-PSRepository', - 'Test-ScriptFileInfo', - 'Uninstall-Module', - 'Uninstall-Script', - 'Unregister-PSRepository', - 'Update-Module', - 'Update-ModuleManifest', - 'Update-Script', - 'Update-ScriptFileInfo') - -VariablesToExport = "*" -AliasesToExport = @('inmo','fimo','upmo','pumo') -FileList = @('PSModule.psm1', - 'PSGet.Format.ps1xml', - 'PSGet.Resource.psd1') -RequiredModules = @(@{ModuleName='PackageManagement';ModuleVersion='1.1.7.0'}) -PrivateData = @{ - "PackageManagementProviders" = 'PSModule.psm1' - "SupportedPowerShellGetFormatVersions" = @('1.x','2.x') - PSData = @{ - Tags = @('Packagemanagement', - 'Provider', - 'PSEdition_Desktop', - 'PSEdition_Core', - 'Linux', - 'Mac') - ProjectUri = 'https://go.microsoft.com/fwlink/?LinkId=828955' - LicenseUri = 'https://go.microsoft.com/fwlink/?LinkId=829061' - ReleaseNotes = @' + RootModule = 'PSModule.psm1' + ModuleVersion = '2.1.1' + GUID = '1d73a601-4a6c-43c5-ba3f-619b18bbb404' + Author = 'Microsoft Corporation' + CompanyName = 'Microsoft Corporation' + Copyright = '(c) Microsoft Corporation. All rights reserved.' + Description = 'PowerShell module with commands for discovering, installing, updating and publishing the PowerShell artifacts like Modules, DSC Resources, Role Capabilities and Scripts.' + PowerShellVersion = '3.0' + FormatsToProcess = 'PSGet.Format.ps1xml' + FunctionsToExport = @( + 'Find-Command', + 'Find-DSCResource', + 'Find-Module', + 'Find-RoleCapability', + 'Find-Script', + 'Get-InstalledModule', + 'Get-InstalledScript', + 'Get-PSRepository', + 'Install-Module', + 'Install-Script', + 'New-ScriptFileInfo', + 'Publish-Module', + 'Publish-Script', + 'Register-PSRepository', + 'Save-Module', + 'Save-Script', + 'Set-PSRepository', + 'Test-ScriptFileInfo', + 'Uninstall-Module', + 'Uninstall-Script', + 'Unregister-PSRepository', + 'Update-Module', + 'Update-ModuleManifest', + 'Update-Script', + 'Update-ScriptFileInfo') + + VariablesToExport = "*" + AliasesToExport = @('inmo', 'fimo', 'upmo', 'pumo') + FileList = @('PSModule.psm1', + 'PSGet.Format.ps1xml', + 'PSGet.Resource.psd1') + RequiredModules = @(@{ModuleName = 'PackageManagement'; ModuleVersion = '1.1.7.0'}) + PrivateData = @{ + "PackageManagementProviders" = 'PSModule.psm1' + "SupportedPowerShellGetFormatVersions" = @('1.x', '2.x') + PSData = @{ + Tags = @('Packagemanagement', + 'Provider', + 'PSEdition_Desktop', + 'PSEdition_Core', + 'Linux', + 'Mac') + ProjectUri = 'https://go.microsoft.com/fwlink/?LinkId=828955' + LicenseUri = 'https://go.microsoft.com/fwlink/?LinkId=829061' + ReleaseNotes = @' +## 2.1.1 + +- Fix DSC resource folder structure + ## 2.1.0 Breaking Change @@ -243,8 +247,8 @@ Bug fixes * Proxy Authentication support. * Responses to a number of user requests and issues. '@ + } } -} -HelpInfoURI = 'http://go.microsoft.com/fwlink/?linkid=855963' + HelpInfoURI = 'http://go.microsoft.com/fwlink/?linkid=855963' } From 0a2c684f4bd0187c6d4c65e9e4f26fc82fb28e5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hei=C3=B0ar=20H=C3=B3lmberg=20J=C3=B3nsson?= Date: Fri, 12 Apr 2019 11:18:01 +0000 Subject: [PATCH 03/19] Remove validation on NugetApiKey parameter Removed _ValidateNotNullOrEmpty_ from NugetApiKey and implemented checking for the parameter in Publish-Module and Publish-PSArtifactUtility similar to how credentials are added conditionally. --- .../functions/Publish-PSArtifactUtility.ps1 | 12 ++++++++---- .../public/psgetfunctions/Publish-Module.ps1 | 19 +++---------------- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 b/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 index b1f662d9..b5571a54 100644 --- a/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 +++ b/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 @@ -28,8 +28,7 @@ function Publish-PSArtifactUtility [string] $Repository, - [Parameter(Mandatory=$true)] - [ValidateNotNullOrEmpty()] + [Parameter(Mandatory=$false)] [string] $NugetApiKey, @@ -531,7 +530,10 @@ $CsprojContent = @" $ArgumentList += 'push' $ArgumentList += "`"$NupkgPath`"" $ArgumentList += @('--source', "`"$($Destination.TrimEnd('\'))`"") - $ArgumentList += @('--api-key', "`"$NugetApiKey`"") + + if ($PSBoundParameters.Containskey('NugetApiKey')) { + $ArgumentList += @('--api-key', "`"$NugetApiKey`"") + } } elseif($script:NuGetExePath) { $StartProcess_params['FilePath'] = $script:NuGetExePath @@ -539,8 +541,10 @@ $CsprojContent = @" $ArgumentList = @('push') $ArgumentList += "`"$NupkgPath`"" $ArgumentList += @('-source', "`"$($Destination.TrimEnd('\'))`"") - $ArgumentList += @('-apikey', "`"$NugetApiKey`"") $ArgumentList += '-NonInteractive' + if ($PSBoundParameters.Containskey('NugetApiKey')) { + $ArgumentList += @('--api-key', "`"$NugetApiKey`"") + } } $StartProcess_params['ArgumentList'] = $ArgumentList diff --git a/src/PowerShellGet/public/psgetfunctions/Publish-Module.ps1 b/src/PowerShellGet/public/psgetfunctions/Publish-Module.ps1 index 4a3d1f4b..035230ac 100644 --- a/src/PowerShellGet/public/psgetfunctions/Publish-Module.ps1 +++ b/src/PowerShellGet/public/psgetfunctions/Publish-Module.ps1 @@ -28,7 +28,6 @@ function Publish-Module { $RequiredVersion, [Parameter()] - [ValidateNotNullOrEmpty()] [string] $NuGetApiKey, @@ -151,20 +150,6 @@ function Publish-Module { $message = $LocalizedData.PublishLocation -f ($DestinationLocation) Write-Verbose -Message $message - if (-not $NuGetApiKey.Trim()) { - if (Microsoft.PowerShell.Management\Test-Path -Path $DestinationLocation) { - $NuGetApiKey = "$(Get-Random)" - } - else { - $message = $LocalizedData.NuGetApiKeyIsRequiredForNuGetBasedGalleryService -f ($Repository, $DestinationLocation) - ThrowError -ExceptionName "System.ArgumentException" ` - -ExceptionMessage $message ` - -ErrorId "NuGetApiKeyIsRequiredForNuGetBasedGalleryService" ` - -CallerPSCmdlet $PSCmdlet ` - -ErrorCategory InvalidArgument - } - } - $providerName = Get-ProviderName -PSCustomObject $moduleSource if ($providerName -ne $script:NuGetProviderName) { $message = $LocalizedData.PublishModuleSupportsOnlyNuGetBasedPublishLocations -f ($moduleSource.PublishLocation, $Repository, $Repository) @@ -543,7 +528,6 @@ function Publish-Module { $PublishPSArtifactUtility_Params = @{ PSModuleInfo = $moduleInfo ManifestPath = $manifestPath - NugetApiKey = $NuGetApiKey Destination = $DestinationLocation Repository = $Repository NugetPackageRoot = $tempModulePath @@ -561,6 +545,9 @@ function Publish-Module { if ($PSBoundParameters.Containskey('Credential')) { $PublishPSArtifactUtility_Params.Add('Credential', $Credential) } + if ($PSBoundParameters.Containskey('NugetApiKey')) { + $PublishPSArtifactUtility_Params.Add('NugetApiKey', $NuGetApiKey) + } Publish-PSArtifactUtility @PublishPSArtifactUtility_Params } } From ff408564a3e5711b53fe9fd4f3a9c34500ecae79 Mon Sep 17 00:00:00 2001 From: Leandro Wajswajn Pereyra Date: Wed, 1 May 2019 10:37:13 -0300 Subject: [PATCH 04/19] Added scopeto Update-Module. Added localized error message (#471) --- src/PowerShellGet/PSGet.Resource.psd1 | 1 + .../public/psgetfunctions/Update-Module.ps1 | 22 ++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/PowerShellGet/PSGet.Resource.psd1 b/src/PowerShellGet/PSGet.Resource.psd1 index b6704d17..8d472b70 100644 --- a/src/PowerShellGet/PSGet.Resource.psd1 +++ b/src/PowerShellGet/PSGet.Resource.psd1 @@ -22,6 +22,7 @@ ConvertFrom-StringData @' RequiredVersionAllowedOnlyWithSingleModuleName=The RequiredVersion parameter is allowed only when a single module name is specified as the value of the Name parameter, without any wildcard characters. MinimumVersionIsGreaterThanMaximumVersion=The specified MinimumVersion '{0}' is greater than the specified MaximumVersion '{1}'. AllowPrereleaseRequiredToUsePrereleaseStringInVersion=The '-AllowPrerelease' parameter must be specified when using the Prerelease string in MinimumVersion, MaximumVersion, or RequiredVersion. + UpdateModuleAdminPrivilegeRequiredForAllUsersScope=Administrator rights are required to update modules in '{0}'. Log on to the computer with an account that has Administrator rights, and then try again, or update '{1}' by adding "-Scope CurrentUser" to your command. You can also try running the Windows PowerShell session with elevated rights (Run as Administrator). InstallModuleAdminPrivilegeRequiredForAllUsersScope=Administrator rights are required to install modules in '{0}'. Log on to the computer with an account that has Administrator rights, and then try again, or install '{1}' by adding "-Scope CurrentUser" to your command. You can also try running the Windows PowerShell session with elevated rights (Run as Administrator). InstallScriptAdminPrivilegeRequiredForAllUsersScope=Administrator rights are required to install scripts in '{0}'. Log on to the computer with an account that has Administrator rights, and then try again, or install '{1}' by adding "-Scope CurrentUser" to your command. You can also try running the Windows PowerShell session with elevated rights (Run as Administrator). AdministratorRightsNeededOrSpecifyCurrentUserScope=Administrator rights are required to install or update. Log on to the computer with an account that has Administrator rights, and then try again, or install by adding "-Scope CurrentUser" to your command. You can also try running the Windows PowerShell session with elevated rights (Run as Administrator). diff --git a/src/PowerShellGet/public/psgetfunctions/Update-Module.ps1 b/src/PowerShellGet/public/psgetfunctions/Update-Module.ps1 index 8a24deb4..92adff7d 100644 --- a/src/PowerShellGet/public/psgetfunctions/Update-Module.ps1 +++ b/src/PowerShellGet/public/psgetfunctions/Update-Module.ps1 @@ -26,6 +26,11 @@ function Update-Module { [PSCredential] $Credential, + [Parameter()] + [ValidateSet("CurrentUser", "AllUsers")] + [string] + $Scope, + [Parameter(ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [Uri] @@ -51,6 +56,17 @@ function Update-Module { Begin { Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential + if ($Scope -eq "AllUsers" -and -not (Test-RunningAsElevated)) { + # Throw an error when Update-Module is used as a non-admin user and '-Scope AllUsers' + $message = $LocalizedData.UpdateModuleAdminPrivilegeRequiredForAllUsersScope -f @($script:programFilesModulesPath, $script:MyDocumentsModulesPath) + + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage $message ` + -ErrorId "UpdateModuleAdminPrivilegeRequiredForAllUsersScope" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidArgument + } + # Module names already tried in the current pipeline $moduleNamesInPipeline = @() } @@ -135,7 +151,11 @@ function Update-Module { $PSBoundParameters["PackageManagementProvider"] = $providerName $PSBoundParameters["InstallUpdate"] = $true - $PSBoundParameters["Scope"] = Get-InstallationScope -PreviousInstallLocation $psgetItemInfo.InstalledLocation -CurrentUserPath $script:MyDocumentsModulesPath + if (-not $Scope) { + $Scope = Get-InstallationScope -PreviousInstallLocation $psgetItemInfo.InstalledLocation -CurrentUserPath $script:MyDocumentsModulesPath + } + + $PSBoundParameters["Scope"] = $Scope $sid = PackageManagement\Install-Package @PSBoundParameters } From 483dadad3f3b15e365cbfb91643d8886ae88ed25 Mon Sep 17 00:00:00 2001 From: Edwin Young Date: Wed, 1 May 2019 13:43:47 -0700 Subject: [PATCH 05/19] update tests (#469) * fix prerelease behavior * these tests are intermittently failing on appveyor (networking issues?) * delete unused file * autoformat; add -ErrorAction to some tests to get better info * fix skip syntax * extra debug info * fix count and add more debug info --- Tests/PSGetPublishModule.Tests.ps1 | 8 +- Tests/PSGetRequireLicenseAcceptance.Tests.ps1 | 399 ++++--- .../private/functions/New-NuspecFile.ps1 | 2 +- tests/PSGetRequireLicenseAcceptance.ps1 | 991 ------------------ 4 files changed, 181 insertions(+), 1219 deletions(-) delete mode 100644 tests/PSGetRequireLicenseAcceptance.ps1 diff --git a/Tests/PSGetPublishModule.Tests.ps1 b/Tests/PSGetPublishModule.Tests.ps1 index c62a12cb..971afdfd 100644 --- a/Tests/PSGetPublishModule.Tests.ps1 +++ b/Tests/PSGetPublishModule.Tests.ps1 @@ -1176,7 +1176,7 @@ Describe PowerShell.PSGet.PublishModuleTests -Tags 'BVT','InnerLoop' { finally { Install-NuGetBinaries } - } -Skip:$($PSEdition -eq 'Core') + } -Skip:$($PSEdition -eq 'Core' -or $env:APPVEYOR_TEST_PASS -eq 'True') # Purpose: Validate that Publish-Module prompts to install NuGet.exe if NuGet.exe file is not found # @@ -1234,7 +1234,7 @@ Describe PowerShell.PSGet.PublishModuleTests -Tags 'BVT','InnerLoop' { finally { Install-NuGetBinaries } - } -Skip:$($PSEdition -eq 'Core') + } -Skip:$($PSEdition -eq 'Core' -or $env:APPVEYOR_TEST_PASS -eq 'True') # Purpose: Validate that Publish-Module prompts to upgrade NuGet.exe if local NuGet.exe file is less than minimum required version # @@ -1300,7 +1300,7 @@ Describe PowerShell.PSGet.PublishModuleTests -Tags 'BVT','InnerLoop' { finally { Install-NuGetBinaries } - } -Skip:$($PSEdition -eq 'Core') + } -Skip:$($PSEdition -eq 'Core' -or $env:APPVEYOR_TEST_PASS -eq 'True') # Purpose: Validate that Publish-Module prompts to install NuGet.exe if file not found # @@ -1357,7 +1357,7 @@ Describe PowerShell.PSGet.PublishModuleTests -Tags 'BVT','InnerLoop' { finally { Install-NuGetBinaries } - } -Skip:$($PSEdition -eq 'Core') + } -Skip:$($PSEdition -eq 'Core' -or $env:APPVEYOR_TEST_PASS -eq 'True') } Describe PowerShell.PSGet.PublishModuleTests.P1 -Tags 'P1','OuterLoop' { diff --git a/Tests/PSGetRequireLicenseAcceptance.Tests.ps1 b/Tests/PSGetRequireLicenseAcceptance.Tests.ps1 index fe6c2330..d081d656 100644 --- a/Tests/PSGetRequireLicenseAcceptance.Tests.ps1 +++ b/Tests/PSGetRequireLicenseAcceptance.Tests.ps1 @@ -7,7 +7,7 @@ <# Name: PowerShell.PSGet.PSGetRequireLicenseAcceptance - Description: Tests for Require License Acceptance functionality + Description: Tests for Require License Acceptance functionality #> function SuiteSetup { @@ -18,7 +18,7 @@ function SuiteSetup { $script:MyDocumentsModulesPath = Get-CurrentUserModulesPath $script:PSGetLocalAppDataPath = Get-PSGetLocalAppDataPath $script:TempPath = Get-TempPath - $script:PSGetRequireLicenseAcceptanceFormatVersion = "2.0" + $script:PSGetRequireLicenseAcceptanceFormatVersion = "2.0" #Bootstrap NuGet binaries Install-NuGetBinaries @@ -27,10 +27,9 @@ function SuiteSetup { RemoveItem $script:PSGalleryRepoPath $null = New-Item -Path $script:PSGalleryRepoPath -ItemType Directory -Force - $script:moduleSourcesFilePath= Join-Path $script:PSGetLocalAppDataPath "PSRepositories.xml" + $script:moduleSourcesFilePath = Join-Path $script:PSGetLocalAppDataPath "PSRepositories.xml" $script:moduleSourcesBackupFilePath = Join-Path $script:PSGetLocalAppDataPath "PSRepositories.xml_$(get-random)_backup" - if(Test-Path $script:moduleSourcesFilePath) - { + if (Test-Path $script:moduleSourcesFilePath) { Rename-Item $script:moduleSourcesFilePath $script:moduleSourcesBackupFilePath -Force } @@ -40,7 +39,7 @@ function SuiteSetup { AssertEquals $modSource.SourceLocation $script:PSGalleryRepoPath "Test repository's SourceLocation is not set properly" AssertEquals $modSource.PublishLocation $script:PSGalleryRepoPath "Test repository's PublishLocation is not set properly" - $script:ApiKey="TestPSGalleryApiKey" + $script:ApiKey = "TestPSGalleryApiKey" # Create temp module to be published $script:TempModulesPath = Join-Path -Path $script:TempPath -ChildPath "PSGet_$(Get-Random)" @@ -52,12 +51,10 @@ function SuiteSetup { } function SuiteCleanup { - if(Test-Path $script:moduleSourcesBackupFilePath) - { + if (Test-Path $script:moduleSourcesBackupFilePath) { Move-Item $script:moduleSourcesBackupFilePath $script:moduleSourcesFilePath -Force } - else - { + else { RemoveItem $script:moduleSourcesFilePath } @@ -68,7 +65,7 @@ function SuiteCleanup { RemoveItem $script:TempModulesPath } -Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.UpdateModuleManifest -Tags 'BVT','InnerLoop' { +Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.UpdateModuleManifest -Tags 'BVT', 'InnerLoop' { BeforeAll { SuiteSetup } @@ -81,25 +78,25 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.UpdateModuleManifest -Ta RemoveItem "$script:PSGalleryRepoPath\*" RemoveItem "$script:PublishModuleBase\*" } - + # Purpose: Validate Update-ModuleManifest sets RequireLicenseAcceptance flag # # Action: # Update-ModuleManifest -RequireLicenseAcceptance # Expected Result: Update-ModuleManifest should update the manifest with RequireLicenseAcceptance value # - It UpdateModuleManifestWithRequireLicenseAcceptance { - New-ModuleManifest -Path "$script:PublishModuleBase\$script:PublishModuleName.psd1" - Update-ModuleManifest -Path "$script:PublishModuleBase\$script:PublishModuleName.psd1" -RequireLicenseAcceptance - $moduleInfo = Test-ModuleManifest -Path "$script:PublishModuleBase\$script:PublishModuleName.psd1" - $moduleInfo.PrivateData.PSData.RequireLicenseAcceptance | should be $true - } + It UpdateModuleManifestWithRequireLicenseAcceptance { + New-ModuleManifest -Path "$script:PublishModuleBase\$script:PublishModuleName.psd1" + Update-ModuleManifest -Path "$script:PublishModuleBase\$script:PublishModuleName.psd1" -RequireLicenseAcceptance + $moduleInfo = Test-ModuleManifest -Path "$script:PublishModuleBase\$script:PublishModuleName.psd1" + $moduleInfo.PrivateData.PSData.RequireLicenseAcceptance | should be $true + } } -Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.Publish -Tags 'BVT','InnerLoop' { - # Not executing these tests on Linux and MacOS as +Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.Publish -Tags 'BVT', 'InnerLoop' { + # Not executing these tests on Linux and MacOS as # the total execution time is exceeding allowed 50 min in TravisCI daily builds. - if($IsMacOS -or $IsLinux) { + if ($IsMacOS -or $IsLinux) { return } @@ -122,7 +119,7 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.Publish -Tags 'BVT','Inn RemoveItem "$script:ProgramFilesModulesPath\$script:PublishModuleName" RemoveItem "$script:PublishModuleBase\*" } - + # Purpose: Publish module that requires license acceptance # # Action: @@ -134,13 +131,13 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.Publish -Tags 'BVT','Inn # It "PublishModuleRequiresLicenseAcceptance" { $version = "1.0" - New-ModuleManifest -Path $ModuleManifestFilePath -ModuleVersion $version -Description "$script:PublishModuleName module" -NestedModules "$script:PublishModuleName.psm1" + New-ModuleManifest -Path $ModuleManifestFilePath -ModuleVersion $version -Description "$script:PublishModuleName module" -NestedModules "$script:PublishModuleName.psm1" Update-ModuleManifest -Path $ModuleManifestFilePath -LicenseUri "http://$script:PublishModuleName.com/license" Update-ModuleManifest -Path $ModuleManifestFilePath -RequireLicenseAcceptance Set-Content $LicenseFilePath -Value "LicenseTerms" - + Publish-Module -Path $script:PublishModuleBase -NuGetApiKey $script:ApiKey - $psgetItemInfo = Find-Module $script:PublishModuleName -RequiredVersion $version + $psgetItemInfo = Find-Module $script:PublishModuleName -RequiredVersion $version $psgetItemInfo.AdditionalMetadata.requireLicenseAcceptance | should be "True" $psgetItemInfo.PowerShellGetFormatVersion | should be $script:PSGetRequireLicenseAcceptanceFormatVersion } @@ -149,40 +146,40 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.Publish -Tags 'BVT','Inn # # Action: # Update-ModuleManifest -RequireLicenseAcceptance - # Update-ModuleManifest -LicenseUri + # Update-ModuleManifest -LicenseUri # Publish-Module # Expected Result: It fails with LicenseTxtNotFound error # It "PublishModuleWithoutLicenseTxt" { $version = "1.0" - New-ModuleManifest -Path $ModuleManifestFilePath -ModuleVersion $version -Description "$script:PublishModuleName module" -NestedModules "$script:PublishModuleName.psm1" + New-ModuleManifest -Path $ModuleManifestFilePath -ModuleVersion $version -Description "$script:PublishModuleName module" -NestedModules "$script:PublishModuleName.psm1" Update-ModuleManifest -Path $ModuleManifestFilePath -LicenseUri "http://$script:PublishModuleName.com/license" - Update-ModuleManifest -Path $ModuleManifestFilePath -RequireLicenseAcceptance - - AssertFullyQualifiedErrorIdEquals -scriptblock {Publish-Module -Path $script:PublishModuleBase -NuGetApiKey $script:ApiKey -WarningAction SilentlyContinue}` - -expectedFullyQualifiedErrorId 'LicenseTxtNotFound,Publish-PSArtifactUtility' + Update-ModuleManifest -Path $ModuleManifestFilePath -RequireLicenseAcceptance + + AssertFullyQualifiedErrorIdEquals -scriptblock { Publish-Module -Path $script:PublishModuleBase -NuGetApiKey $script:ApiKey -WarningAction SilentlyContinue }` + -expectedFullyQualifiedErrorId 'LicenseTxtNotFound,Publish-PSArtifactUtility' } - + # Purpose: Publish module without LicenseURI # # Action: - # Update-ModuleManifest -RequireLicenseAcceptance + # Update-ModuleManifest -RequireLicenseAcceptance # Add License.txt # Publish-Module # Expected Result: It fails with LicenseUriNotSpecified error # It "PublishModuleWithoutLicenseUri" { $version = "1.0" - New-ModuleManifest -Path $ModuleManifestFilePath -ModuleVersion $version -Description "$script:PublishModuleName module" -NestedModules "$script:PublishModuleName.psm1" - Update-ModuleManifest -Path $ModuleManifestFilePath -RequireLicenseAcceptance - Set-Content $LicenseFilePath -Value "LicenseTerms" - AssertFullyQualifiedErrorIdEquals -scriptblock {Publish-Module -Path $script:PublishModuleBase -NuGetApiKey $script:ApiKey -WarningAction SilentlyContinue}` - -expectedFullyQualifiedErrorId 'LicenseUriNotSpecified,Publish-PSArtifactUtility' + New-ModuleManifest -Path $ModuleManifestFilePath -ModuleVersion $version -Description "$script:PublishModuleName module" -NestedModules "$script:PublishModuleName.psm1" + Update-ModuleManifest -Path $ModuleManifestFilePath -RequireLicenseAcceptance + Set-Content $LicenseFilePath -Value "LicenseTerms" + AssertFullyQualifiedErrorIdEquals -scriptblock { Publish-Module -Path $script:PublishModuleBase -NuGetApiKey $script:ApiKey -WarningAction SilentlyContinue }` + -expectedFullyQualifiedErrorId 'LicenseUriNotSpecified,Publish-PSArtifactUtility' } - + # Purpose: Publish module without setting requireLicenseAcceptance # # Action: @@ -193,20 +190,20 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.Publish -Tags 'BVT','Inn # It "PublishModuleNoRequireLicenseAcceptance" { $version = "1.0" - New-ModuleManifest -Path $ModuleManifestFilePath -ModuleVersion $version -Description "$script:PublishModuleName module" -NestedModules "$script:PublishModuleName.psm1" - Update-ModuleManifest -Path $ModuleManifestFilePath -LicenseUri "http://$script:PublishModuleName.com/license" + New-ModuleManifest -Path $ModuleManifestFilePath -ModuleVersion $version -Description "$script:PublishModuleName module" -NestedModules "$script:PublishModuleName.psm1" + Update-ModuleManifest -Path $ModuleManifestFilePath -LicenseUri "http://$script:PublishModuleName.com/license" Set-Content $LicenseFilePath -Value "LicenseTerms" - + Publish-Module -Path $script:PublishModuleBase -NuGetApiKey $script:ApiKey $psgetItemInfo = Find-Module $script:PublishModuleName -RequiredVersion $version - $psgetItemInfo.AdditionalMetadata.requireLicenseAcceptance | should be "False" + $psgetItemInfo.AdditionalMetadata.requireLicenseAcceptance | should be "False" } } function InstallSuiteSetup { Import-Module "$PSScriptRoot\PSGetTestUtils.psm1" -WarningAction SilentlyContinue Import-Module "$PSScriptRoot\Asserts.psm1" -WarningAction SilentlyContinue - + $script:ProgramFilesModulesPath = Get-AllUsersModulesPath $script:MyDocumentsModulesPath = Get-CurrentUserModulesPath $script:PSGetLocalAppDataPath = Get-PSGetLocalAppDataPath @@ -218,27 +215,24 @@ function InstallSuiteSetup { $psgetModuleInfo = Import-Module PowerShellGet -Global -Force -Passthru Import-LocalizedData script:LocalizedData -filename PSGet.Resource.psd1 -BaseDirectory $psgetModuleInfo.ModuleBase - $script:moduleSourcesFilePath= Join-Path $script:PSGetLocalAppDataPath "PSRepositories.xml" + $script:moduleSourcesFilePath = Join-Path $script:PSGetLocalAppDataPath "PSRepositories.xml" $script:moduleSourcesBackupFilePath = Join-Path $script:PSGetLocalAppDataPath "PSRepositories.xml_$(get-random)_backup" - if(Test-Path $script:moduleSourcesFilePath) - { + if (Test-Path $script:moduleSourcesFilePath) { Rename-Item $script:moduleSourcesFilePath $script:moduleSourcesBackupFilePath -Force } - $Global:PSGallerySourceUri = '' + $Global:PSGallerySourceUri = '' GetAndSet-PSGetTestGalleryDetails -SetPSGallery -PSGallerySourceUri ([REF]$Global:PSGallerySourceUri) -IsScriptSuite - PSGetTestUtils\Uninstall-Module ModuleRequireLicenseAcceptance + PSGetTestUtils\Uninstall-Module ModuleRequireLicenseAcceptance Get-InstalledScript -Name ScriptRequireLicenseAcceptance -ErrorAction SilentlyContinue | Uninstall-Script -Force } function InstallSuiteCleanup { - if(Test-Path $script:moduleSourcesBackupFilePath) - { + if (Test-Path $script:moduleSourcesBackupFilePath) { Move-Item $script:moduleSourcesBackupFilePath $script:moduleSourcesFilePath -Force } - else - { + else { RemoveItem $script:moduleSourcesFilePath } @@ -246,7 +240,7 @@ function InstallSuiteCleanup { $null = Import-PackageProvider -Name PowerShellGet -Force } -Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags 'BVT','InnerLoop' { +Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags 'BVT', 'InnerLoop' { BeforeAll { InstallSuiteSetup @@ -259,9 +253,9 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags AfterEach { Get-InstalledScript -Name ScriptRequireLicenseAcceptance -ErrorAction SilentlyContinue | Uninstall-Script -Force -ErrorAction SilentlyContinue PSGetTestUtils\Uninstall-Module ModuleWithDependency - PSGetTestUtils\Uninstall-Module ModuleRequireLicenseAcceptance - } - + PSGetTestUtils\Uninstall-Module ModuleRequireLicenseAcceptance + } + # Purpose: InstallModuleRequiringLicenseAcceptanceAndNoToPrompt # # Action: Install-Module ModuleRequireLicenseAcceptance @@ -270,24 +264,21 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags # It "InstallModuleRequiringLicenseAcceptanceAndNoToPrompt" { $outputPath = $script:TempPath - $guid = [system.guid]::newguid().tostring() + $guid = [system.guid]::newguid().tostring() $outputFilePath = Join-Path $outputPath "$guid" $runspace = CreateRunSpace $outputFilePath 1 # 2 is mapped to NO in ShouldProcess prompt - $Global:proxy.UI.ChoiceToMake=2 + $Global:proxy.UI.ChoiceToMake = 2 $content = $null - try - { + try { $result = ExecuteCommand $runspace 'Install-Module ModuleRequireLicenseAcceptance -Repository PSGallery' } - finally - { + finally { $fileName = "PromptForChoice-0.txt" $path = join-path $outputFilePath $fileName - if(Test-Path $path) - { + if (Test-Path $path) { $content = get-content $path } @@ -303,7 +294,7 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable AssertNull $res "Install-Module should not install a module if Confirm is not accepted" } ` - -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) + -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) # Purpose: InstallModuleRequiringLicenseAcceptanceAndYesToPrompt # @@ -313,24 +304,21 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags # It "InstallModuleRequiringLicenseAcceptanceAndYesToPrompt" { $outputPath = $script:TempPath - $guid = [system.guid]::newguid().tostring() + $guid = [system.guid]::newguid().tostring() $outputFilePath = Join-Path $outputPath "$guid" $runspace = CreateRunSpace $outputFilePath 1 # 0 is mapped to YES in ShouldProcess prompt - $Global:proxy.UI.ChoiceToMake=0 + $Global:proxy.UI.ChoiceToMake = 0 $content = $null - try - { + try { $result = ExecuteCommand $runspace 'Install-Module ModuleRequireLicenseAcceptance' } - finally - { + finally { $fileName = "PromptForChoice-0.txt" $path = join-path $outputFilePath $fileName - if(Test-Path $path) - { + if (Test-Path $path) { $content = get-content $path } @@ -346,7 +334,7 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleRequireLicenseAcceptance")) "Install-Module should install a module if Confirm is accepted" } ` - -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) + -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) # Purpose: InstallModuleAcceptLicense # @@ -355,11 +343,11 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags # Expected Result: module is installed successfully # It "InstallModuleAcceptLicense" { - Install-Module ModuleRequireLicenseAcceptance -Repository PSGallery -AcceptLicense + Install-Module ModuleRequireLicenseAcceptance -Repository PSGallery -AcceptLicense -ErrorAction Stop -Verbose 4> .\verbose.txt $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable - Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleRequireLicenseAcceptance")) "Install-Module should install the module if -AcceptLicense is specified" + Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleRequireLicenseAcceptance")) "Install-Module should install the module if -AcceptLicense is specified ($($res | Out-String; Get-content .\verbose.txt; Get-Module -ListAvailable | Out-String)) " } - + # Purpose: InstallModuleForce # @@ -367,12 +355,12 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags # # Expected Result: module should fail to install with error ForceAcceptLicense # - It "InstallModuleForce" { - AssertFullyQualifiedErrorIdEquals -scriptblock {Install-Module ModuleRequireLicenseAcceptance -Repository PSGallery -Force}` - -expectedFullyQualifiedErrorId 'ForceAcceptLicense,Install-Module' + It "InstallModuleForce" { + AssertFullyQualifiedErrorIdEquals -scriptblock { Install-Module ModuleRequireLicenseAcceptance -Repository PSGallery -Force }` + -expectedFullyQualifiedErrorId 'ForceAcceptLicense,Install-Module' } - + # Purpose: InstallModuleWithDependencyAndYesToPrompt # # Action: Install-Module ModuleWithDependency @@ -381,24 +369,21 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags # It "InstallModuleWithDependencyAndYesToPrompt" { $outputPath = $script:TempPath - $guid = [system.guid]::newguid().tostring() + $guid = [system.guid]::newguid().tostring() $outputFilePath = Join-Path $outputPath "$guid" $runspace = CreateRunSpace $outputFilePath 1 # 0 is mapped to YES in ShouldProcess prompt - $Global:proxy.UI.ChoiceToMake=0 + $Global:proxy.UI.ChoiceToMake = 0 $content = $null - try - { + try { $result = ExecuteCommand $runspace 'Install-Module ModuleWithDependency' } - finally - { + finally { $fileName = "PromptForChoice-0.txt" $path = join-path $outputFilePath $fileName - if(Test-Path $path) - { + if (Test-Path $path) { $content = get-content $path } @@ -408,7 +393,7 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags $itemInfo = Find-Module ModuleRequireLicenseAcceptance -Repository PSGallery $installShouldProcessMessage = $script:LocalizedData.AcceptanceLicenseQuery -f ($itemInfo.Name) - Assert ($content -and ($content -match $installShouldProcessMessage)) "Install Module confirm prompt is not working, Expected:$installShouldProcessMessage, Actual:$content" + Assert ($content -and ($content -match $installShouldProcessMessage)) "Install Module confirm prompt is not working, Expected:$installShouldProcessMessage, Actual:$content" $res = Get-Module ModuleWithDependency -ListAvailable Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleWithDependency")) "Install-Module should install a module if Confirm is accepted" @@ -416,7 +401,7 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleRequireLicenseAcceptance")) "Install-Module should install a module if Confirm is accepted" } ` - -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) + -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) # Purpose: InstallModuleWithDependencyAndNoToPrompt # @@ -426,24 +411,21 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags # It "InstallModuleWithDependencyAndNoToPrompt" { $outputPath = $script:TempPath - $guid = [system.guid]::newguid().tostring() + $guid = [system.guid]::newguid().tostring() $outputFilePath = Join-Path $outputPath "$guid" $runspace = CreateRunSpace $outputFilePath 1 # 2 is mapped to NO in ShouldProcess prompt - $Global:proxy.UI.ChoiceToMake=2 + $Global:proxy.UI.ChoiceToMake = 2 $content = $null - try - { + try { $result = ExecuteCommand $runspace 'Install-Module ModuleWithDependency -Repository PSGallery' } - finally - { + finally { $fileName = "PromptForChoice-0.txt" $path = join-path $outputFilePath $fileName - if(Test-Path $path) - { + if (Test-Path $path) { $content = get-content $path } @@ -462,7 +444,7 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags $res = Get-Module ModuleWithDependency -ListAvailable AssertNull $res "Install-Module should not install a module if Confirm is not accepted" } ` - -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) + -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) # Purpose: InstallModuleWithDependencyAcceptLicense # @@ -471,14 +453,14 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags # Expected Result: module is installed successfully # It "InstallModuleWithDependencyAcceptLicense" { - Install-Module ModuleWithDependency -AcceptLicense + Install-Module ModuleWithDependency -AcceptLicense -ErrorAction Stop $res = Get-Module ModuleWithDependency -ListAvailable Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleWithDependency")) "Install-Module should install the module if -AcceptLicense is specified" - + $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleRequireLicenseAcceptance")) "Install-Module should install the module if -AcceptLicense is specified" - } + } # Purpose: InstallScriptAndYesToPrompt # @@ -488,24 +470,21 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags # It "InstallScriptAndYesToPrompt" { $outputPath = $script:TempPath - $guid = [system.guid]::newguid().tostring() + $guid = [system.guid]::newguid().tostring() $outputFilePath = Join-Path $outputPath "$guid" $runspace = CreateRunSpace $outputFilePath 1 # 0 is mapped to YES in ShouldProcess prompt - $Global:proxy.UI.ChoiceToMake=0 + $Global:proxy.UI.ChoiceToMake = 0 $content = $null - try - { + try { $result = ExecuteCommand $runspace 'Install-Script ScriptRequireLicenseAcceptance -NoPathUpdate' } - finally - { + finally { $fileName = "PromptForChoice-0.txt" $path = join-path $outputFilePath $fileName - if(Test-Path $path) - { + if (Test-Path $path) { $content = get-content $path } @@ -516,16 +495,16 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags $itemInfo = Find-Module ModuleRequireLicenseAcceptance -Repository PSGallery $installShouldProcessMessage = $script:LocalizedData.AcceptanceLicenseQuery -f ($itemInfo.Name) Assert ($content -and ($content -match $installShouldProcessMessage)) "Install script confirm prompt is not working, Expected:$installShouldProcessMessage, Actual:$content" - + $res = Get-InstalledScript ScriptRequireLicenseAcceptance AssertEquals $res.Name "ScriptRequireLicenseAcceptance" "Install-Script failed to install $scriptName, $res" $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleRequireLicenseAcceptance")) "Install-Module should install a module if Confirm is accepted" } ` - -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) + -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) + - # Purpose: InstallScriptAndNoToPrompt # # Action: Install-Script ScriptRequireLicenseAcceptance @@ -534,24 +513,21 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags # It "InstallScriptAndNoToPrompt" { $outputPath = $script:TempPath - $guid = [system.guid]::newguid().tostring() + $guid = [system.guid]::newguid().tostring() $outputFilePath = Join-Path $outputPath "$guid" - $runspace = CreateRunSpace $outputFilePath 1 + $runspace = CreateRunSpace $outputFilePath 1 # 2 is mapped to NO in ShouldProcess prompt - $Global:proxy.UI.ChoiceToMake=2 + $Global:proxy.UI.ChoiceToMake = 2 $content = $null - try - { + try { $result = ExecuteCommand $runspace 'Install-Script ScriptRequireLicenseAcceptance -NoPathUpdate' } - finally - { + finally { $fileName = "PromptForChoice-0.txt" $path = join-path $outputFilePath $fileName - if(Test-Path $path) - { + if (Test-Path $path) { $content = get-content $path } @@ -565,13 +541,13 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags $res = Get-InstalledScript ScriptRequireLicenseAcceptance -ErrorAction SilentlyContinue AssertNull $res "Script should not be installed" - + $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable - AssertNull $res "Dependant module should not be installed if Confirm is not accepted" - } ` - -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) + AssertNull $res "Dependant module should not be installed if Confirm is not accepted" + } ` + -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) + - # Purpose: InstallScriptAcceptLicense # # Action: Install-Script ScriptRequireLicenseAcceptance -AcceptLicennse @@ -579,14 +555,14 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags # Expected Result: script and dependant module are installed successfully # It "InstallScriptAcceptLicense" { - Install-Script ScriptRequireLicenseAcceptance -AcceptLicense -NoPathUpdate + Install-Script ScriptRequireLicenseAcceptance -AcceptLicense -NoPathUpdate -ErrorAction Stop $res = Get-InstalledScript ScriptRequireLicenseAcceptance AssertEquals $res.Name "ScriptRequireLicenseAcceptance" "Install-Script failed to install $scriptName, $res" - + $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleRequireLicenseAcceptance")) "Install-Module should install the module if -AcceptLicense is specified" - } + } # Purpose: SaveModuleRequiringLicenseAcceptanceAndNoToPrompt # @@ -596,24 +572,21 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags # It "SaveModuleRequiringLicenseAcceptanceAndNoToPrompt" { $outputPath = $script:TempPath - $guid = [system.guid]::newguid().tostring() + $guid = [system.guid]::newguid().tostring() $outputFilePath = Join-Path $outputPath "$guid" $runspace = CreateRunSpace $outputFilePath 1 # 2 is mapped to NO in ShouldProcess prompt - $Global:proxy.UI.ChoiceToMake=2 + $Global:proxy.UI.ChoiceToMake = 2 $content = $null - try - { + try { $result = ExecuteCommand $runspace "Save-Module ModuleRequireLicenseAcceptance -Path $script:MyDocumentsModulesPath -ErrorAction SilentlyContinue" } - finally - { + finally { $fileName = "PromptForChoice-0.txt" $path = join-path $outputFilePath $fileName - if(Test-Path $path) - { + if (Test-Path $path) { $content = get-content $path } @@ -629,7 +602,7 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable AssertNull $res "Save-Module should not install a module if Confirm is not accepted" } ` - -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) + -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) # Purpose: SaveModuleRequiringLicenseAcceptanceAndYesToPrompt # @@ -639,24 +612,21 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags # It "SaveModuleRequiringLicenseAcceptanceAndYesToPrompt" { $outputPath = $script:TempPath - $guid = [system.guid]::newguid().tostring() + $guid = [system.guid]::newguid().tostring() $outputFilePath = Join-Path $outputPath "$guid" $runspace = CreateRunSpace $outputFilePath 1 # 0 is mapped to YES in ShouldProcess prompt - $Global:proxy.UI.ChoiceToMake=0 + $Global:proxy.UI.ChoiceToMake = 0 $content = $null - try - { + try { $result = ExecuteCommand $runspace "Save-Module ModuleRequireLicenseAcceptance -Path $script:MyDocumentsModulesPath" } - finally - { + finally { $fileName = "PromptForChoice-0.txt" $path = join-path $outputFilePath $fileName - if(Test-Path $path) - { + if (Test-Path $path) { $content = get-content $path } @@ -672,7 +642,7 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleRequireLicenseAcceptance")) "save-Module should save a module if Confirm is accepted" } ` - -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) + -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) # Purpose: SaveModuleAcceptLicense # @@ -681,7 +651,7 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags # Expected Result: module is saved successfully # It "SaveModuleAcceptLicense" { - Save-Module ModuleRequireLicenseAcceptance -Repository PSGallery -AcceptLicense -Path $script:MyDocumentsModulesPath + Save-Module ModuleRequireLicenseAcceptance -Repository PSGallery -AcceptLicense -Path $script:MyDocumentsModulesPath -ErrorAction Stop $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleRequireLicenseAcceptance")) "Install-Module should install the module if -AcceptLicense is specified" } @@ -692,9 +662,9 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags # # Expected Result: module should fail to save with error ForceAcceptLicense # - It "SaveModuleForce" { - AssertFullyQualifiedErrorIdEquals -scriptblock {Save-Module ModuleRequireLicenseAcceptance -Repository PSGallery -Force -Path $script:MyDocumentsModulesPath -WarningAction SilentlyContinue}` - -expectedFullyQualifiedErrorId 'ForceAcceptLicense,Install-Module' + It "SaveModuleForce" { + AssertFullyQualifiedErrorIdEquals -scriptblock { Save-Module ModuleRequireLicenseAcceptance -Repository PSGallery -Force -Path $script:MyDocumentsModulesPath -WarningAction SilentlyContinue }` + -expectedFullyQualifiedErrorId 'ForceAcceptLicense,Install-Module' } # Purpose: SaveModuleWithDependencyAndYesToPrompt @@ -705,24 +675,21 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags # It "SaveModuleWithDependencyAndYesToPrompt" { $outputPath = $script:TempPath - $guid = [system.guid]::newguid().tostring() + $guid = [system.guid]::newguid().tostring() $outputFilePath = Join-Path $outputPath "$guid" $runspace = CreateRunSpace $outputFilePath 1 # 0 is mapped to YES in ShouldProcess prompt - $Global:proxy.UI.ChoiceToMake=0 + $Global:proxy.UI.ChoiceToMake = 0 $content = $null - try - { + try { $result = ExecuteCommand $runspace "Save-Module ModuleWithDependency -Path $script:MyDocumentsModulesPath" } - finally - { + finally { $fileName = "PromptForChoice-0.txt" $path = join-path $outputFilePath $fileName - if(Test-Path $path) - { + if (Test-Path $path) { $content = get-content $path } @@ -732,7 +699,7 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags $itemInfo = Find-Module ModuleRequireLicenseAcceptance -Repository PSGallery $SaveShouldProcessMessage = $script:LocalizedData.AcceptanceLicenseQuery -f ($itemInfo.Name) - Assert ($content -and ($content -match $SaveShouldProcessMessage)) "Save Module confirm prompt is not working, Expected:$installShouldProcessMessage, Actual:$content" + Assert ($content -and ($content -match $SaveShouldProcessMessage)) "Save Module confirm prompt is not working, Expected:$installShouldProcessMessage, Actual:$content" $res = Get-Module ModuleWithDependency -ListAvailable Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleWithDependency")) "Save-Module should Save a module if Confirm is accepted" @@ -740,7 +707,7 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleRequireLicenseAcceptance")) "Save-Module should Save a module if Confirm is accepted" } ` - -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) + -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) # Purpose: SaveModuleWithDependencyAndNoToPrompt # @@ -750,24 +717,21 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags # It "SaveModuleWithDependencyAndNoToPrompt" { $outputPath = $script:TempPath - $guid = [system.guid]::newguid().tostring() + $guid = [system.guid]::newguid().tostring() $outputFilePath = Join-Path $outputPath "$guid" $runspace = CreateRunSpace $outputFilePath 1 # 2 is mapped to NO in ShouldProcess prompt - $Global:proxy.UI.ChoiceToMake=2 + $Global:proxy.UI.ChoiceToMake = 2 $content = $null - try - { + try { $result = ExecuteCommand $runspace "Save-Module ModuleWithDependency -Path $script:MyDocumentsModulesPath -ErrorAction SilentlyContinue" } - finally - { + finally { $fileName = "PromptForChoice-0.txt" $path = join-path $outputFilePath $fileName - if(Test-Path $path) - { + if (Test-Path $path) { $content = get-content $path } @@ -775,7 +739,7 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags RemoveItem $outputFilePath } - $itemInfo = Find-Module ModuleRequireLicenseAcceptance -Repository PSGallery + $itemInfo = Find-Module ModuleRequireLicenseAcceptance -Repository PSGallery $saveShouldProcessMessage = $script:LocalizedData.AcceptanceLicenseQuery -f ($itemInfo.Name) Assert ($content -and ($content -match $saveShouldProcessMessage)) "Save module confirm prompt is not working, Expected:$installShouldProcessMessage, Actual:$content" @@ -786,7 +750,7 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags $res = Get-Module ModuleWithDependency -ListAvailable AssertNull $res "Save-Module should not install a module if Confirm is not accepted" } ` - -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) + -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) # Purpose: SaveModuleWithDependencyAcceptLicense @@ -796,15 +760,15 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags # Expected Result: module is installed successfully # It "SaveModuleWithDependencyAcceptLicense" { - Save-Module ModuleWithDependency -AcceptLicense -Path $script:MyDocumentsModulesPath + Save-Module ModuleWithDependency -AcceptLicense -Path $script:MyDocumentsModulesPath -ErrorAction Stop $res = Get-Module ModuleWithDependency -ListAvailable Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleWithDependency")) "Install-Module should install the module if -AcceptLicense is specified" - + $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleRequireLicenseAcceptance")) "Install-Module should install the module if -AcceptLicense is specified" } - + # Purpose: SaveScriptAndYesToPrompt # # Action: Save-Script ScriptRequireLicenseAcceptance @@ -813,24 +777,21 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags # It "SaveScriptAndYesToPrompt" { $outputPath = $script:TempPath - $guid = [system.guid]::newguid().tostring() + $guid = [system.guid]::newguid().tostring() $outputFilePath = Join-Path $outputPath "$guid" $runspace = CreateRunSpace $outputFilePath 1 # 0 is mapped to YES in ShouldProcess prompt - $Global:proxy.UI.ChoiceToMake=0 + $Global:proxy.UI.ChoiceToMake = 0 $content = $null - try - { + try { $result = ExecuteCommand $runspace "Save-Script ScriptRequireLicenseAcceptance -Path $script:MyDocumentsModulesPath" } - finally - { + finally { $fileName = "PromptForChoice-0.txt" $path = join-path $outputFilePath $fileName - if(Test-Path $path) - { + if (Test-Path $path) { $content = get-content $path } @@ -841,18 +802,17 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags $itemInfo = Find-Module ModuleRequireLicenseAcceptance -Repository PSGallery $SaveShouldProcessMessage = $script:LocalizedData.AcceptanceLicenseQuery -f ($itemInfo.Name) Assert ($content -and ($content -match $SaveShouldProcessMessage)) "Save script confirm prompt is not working, Expected:$installShouldProcessMessage, Actual:$content" - - - - if(-not (Test-Path -Path "$script:MyDocumentsModulesPath\ScriptRequireLicenseAcceptance.ps1" -PathType Leaf)) - { + + + + if (-not (Test-Path -Path "$script:MyDocumentsModulesPath\ScriptRequireLicenseAcceptance.ps1" -PathType Leaf)) { Assert $false "Save-Script should save script $ScriptName" - } + } $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleRequireLicenseAcceptance")) "Save-Module should save a module if Confirm is accepted" } ` - -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) + -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) # Purpose: SaveScriptAcceptLicense # @@ -861,17 +821,16 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags # Expected Result: script and dependant module are Saved successfully # It "SaveScriptAcceptLicense" { - Save-Script ScriptRequireLicenseAcceptance -AcceptLicense -Path $script:MyDocumentsModulesPath + Save-Script ScriptRequireLicenseAcceptance -AcceptLicense -Path $script:MyDocumentsModulesPath -ErrorAction Stop - if(-not (Test-Path -Path "$script:MyDocumentsModulesPath\ScriptRequireLicenseAcceptance.ps1" -PathType Leaf)) - { + if (-not (Test-Path -Path "$script:MyDocumentsModulesPath\ScriptRequireLicenseAcceptance.ps1" -PathType Leaf)) { Assert $false "Save-Script should save script $ScriptName" } - + $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleRequireLicenseAcceptance")) "Save-Module should Save the module if -AcceptLicense is specified" } - + # Purpose: UpdateModuleRequiringLicenseAcceptanceAndNoToPrompt # @@ -880,28 +839,25 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags # Expected Result: Module should not be updated after confirming NO # It "UpdateModuleRequiringLicenseAcceptanceAndNoToPrompt" { - + Install-module ModuleRequireLicenseAcceptance -RequiredVersion 1.0 -AcceptLicense -Force - + $outputPath = $script:TempPath - $guid = [system.guid]::newguid().tostring() + $guid = [system.guid]::newguid().tostring() $outputFilePath = Join-Path $outputPath "$guid" $runspace = CreateRunSpace $outputFilePath 1 # 2 is mapped to NO in ShouldProcess prompt - $Global:proxy.UI.ChoiceToMake=2 + $Global:proxy.UI.ChoiceToMake = 2 $content = $null - try - { + try { $result = ExecuteCommand $runspace 'Update-Module ModuleRequireLicenseAcceptance' } - finally - { + finally { $fileName = "PromptForChoice-0.txt" $path = join-path $outputFilePath $fileName - if(Test-Path $path) - { + if (Test-Path $path) { $content = get-content $path } @@ -916,10 +872,10 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags - $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable + $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleRequireLicenseAcceptance") -and ($res.Version -eq [Version]"1.0")) "Update-Module should not update the module if confirm is declined" } ` - -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) + -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) # Purpose: UpdateModuleRequiringLicenseAcceptanceAndYesToPrompt @@ -933,24 +889,21 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags Install-module ModuleRequireLicenseAcceptance -RequiredVersion 1.0 -AcceptLicense -Force $outputPath = $script:TempPath - $guid = [system.guid]::newguid().tostring() + $guid = [system.guid]::newguid().tostring() $outputFilePath = Join-Path $outputPath "$guid" $runspace = CreateRunSpace $outputFilePath 1 # 0 is mapped to YES in ShouldProcess prompt - $Global:proxy.UI.ChoiceToMake=0 + $Global:proxy.UI.ChoiceToMake = 0 $content = $null - try - { + try { $result = ExecuteCommand $runspace 'Update-Module ModuleRequireLicenseAcceptance' } - finally - { + finally { $fileName = "PromptForChoice-0.txt" $path = join-path $outputFilePath $fileName - if(Test-Path $path) - { + if (Test-Path $path) { $content = get-content $path } @@ -966,7 +919,7 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags $res = Get-InstalledModule ModuleRequireLicenseAcceptance -RequiredVersion 3.0 AssertNotNull $res "Update-Module should Update a module if Confirm is accepted" } ` - -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) + -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) # Purpose: UpdateModuleAcceptLicnese @@ -988,9 +941,9 @@ Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags # # Expected Result: module should fail to Update with error ForceAcceptLicense # - It "UpdateModuleForce" { + It "UpdateModuleForce" { Install-module ModuleRequireLicenseAcceptance -RequiredVersion 1.0 -AcceptLicense -Force - AssertFullyQualifiedErrorIdEquals -scriptblock {Update-Module ModuleRequireLicenseAcceptance -Force}` - -expectedFullyQualifiedErrorId 'ForceAcceptLicense,Update-Module' - } - } + AssertFullyQualifiedErrorIdEquals -scriptblock { Update-Module ModuleRequireLicenseAcceptance -Force }` + -expectedFullyQualifiedErrorId 'ForceAcceptLicense,Update-Module' + } +} diff --git a/src/PowerShellGet/private/functions/New-NuspecFile.ps1 b/src/PowerShellGet/private/functions/New-NuspecFile.ps1 index 2e7fa6ef..e071d20e 100644 --- a/src/PowerShellGet/private/functions/New-NuspecFile.ps1 +++ b/src/PowerShellGet/private/functions/New-NuspecFile.ps1 @@ -8,7 +8,7 @@ function New-NuspecFile { [string]$Id, [Parameter(Mandatory = $true)] - [version]$Version, + [string]$Version, [Parameter(Mandatory = $true)] [string]$Description, diff --git a/tests/PSGetRequireLicenseAcceptance.ps1 b/tests/PSGetRequireLicenseAcceptance.ps1 deleted file mode 100644 index 5d65e848..00000000 --- a/tests/PSGetRequireLicenseAcceptance.ps1 +++ /dev/null @@ -1,991 +0,0 @@ -<##################################################################################### - # File: PSGetRequireLicenseAcceptance.ps1 - # Tests for require license acceptance PSGet module functionality - # - # Copyright (c) Microsoft Corporation, 2014 - #####################################################################################> - -<# - Name: PowerShell.PSGet.PSGetRequireLicenseAcceptance - Description: Tests for Require License Acceptance functionality -#> - -function SuiteSetup { - Import-Module "$PSScriptRoot\PSGetTestUtils.psm1" -WarningAction SilentlyContinue - Import-Module "$PSScriptRoot\Asserts.psm1" -WarningAction SilentlyContinue - - $script:ProgramFilesModulesPath = Get-AllUsersModulesPath - $script:MyDocumentsModulesPath = Get-CurrentUserModulesPath - $script:PSGetLocalAppDataPath = Get-PSGetLocalAppDataPath - $script:TempPath = Get-TempPath - $script:PSGetRequireLicenseAcceptanceFormatVersion = "2.0" - - #Bootstrap NuGet binaries - Install-NuGetBinaries - - $script:PSGalleryRepoPath="$env:SystemDrive\PSGalleryRepo" - RemoveItem $script:PSGalleryRepoPath - $null = New-Item -Path $script:PSGalleryRepoPath -ItemType Directory -Force - - $script:moduleSourcesFilePath= Join-Path $script:PSGetLocalAppDataPath "PSRepositories.xml" - $script:moduleSourcesBackupFilePath = Join-Path $script:PSGetLocalAppDataPath "PSRepositories.xml_$(get-random)_backup" - if(Test-Path $script:moduleSourcesFilePath) - { - Rename-Item $script:moduleSourcesFilePath $script:moduleSourcesBackupFilePath -Force - } - - Set-PSGallerySourceLocation -Location $script:PSGalleryRepoPath -PublishLocation $script:PSGalleryRepoPath - - $modSource = Get-PSRepository -Name "PSGallery" - AssertEquals $modSource.SourceLocation $script:PSGalleryRepoPath "Test repository's SourceLocation is not set properly" - AssertEquals $modSource.PublishLocation $script:PSGalleryRepoPath "Test repository's PublishLocation is not set properly" - - $script:ApiKey="TestPSGalleryApiKey" - - # Create temp module to be published - $script:TempModulesPath="$env:LocalAppData\temp\PSGet_$(Get-Random)" - $null = New-Item -Path $script:TempModulesPath -ItemType Directory -Force - - $script:PublishModuleName = "RequireLicenseAcceptancePublishModule" - $script:PublishModuleBase = Join-Path $script:TempModulesPath $script:PublishModuleName - $null = New-Item -Path $script:PublishModuleBase -ItemType Directory -Force -} - -function SuiteCleanup { - if(Test-Path $script:moduleSourcesBackupFilePath) - { - Move-Item $script:moduleSourcesBackupFilePath $script:moduleSourcesFilePath -Force - } - else - { - RemoveItem $script:moduleSourcesFilePath - } - - # Import the PowerShellGet provider to reload the repositories. - $null = Import-PackageProvider -Name PowerShellGet -Force - - RemoveItem $script:PSGalleryRepoPath - RemoveItem $script:TempModulesPath -} - -Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.UpdateModuleManifest -Tags 'BVT','InnerLoop' { - BeforeAll { - SuiteSetup - } - - AfterAll { - SuiteCleanup - } - - AfterEach { - RemoveItem "$script:PSGalleryRepoPath\*" - RemoveItem "$script:PublishModuleBase\*" - } - - # Purpose: Validate Update-ModuleManifest sets RequireLicenseAcceptance flag - # - # Action: - # Update-ModuleManifest -RequireLicenseAcceptance - # Expected Result: Update-ModuleManifest should update the manifest with RequireLicenseAcceptance value - # - It UpdateModuleManifestWithRequireLicenseAcceptance { - New-ModuleManifest -Path "$script:PublishModuleBase\$script:PublishModuleName.psd1" - Update-ModuleManifest -Path "$script:PublishModuleBase\$script:PublishModuleName.psd1" -RequireLicenseAcceptance - $moduleInfo = Test-ModuleManifest -Path "$script:PublishModuleBase\$script:PublishModuleName.psd1" - $moduleInfo.PrivateData.PSData.RequireLicenseAcceptance | should be $true - } -} - -Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.Publish -Tags 'BVT','InnerLoop' { - if($PSEdition -eq 'Core') { - return - } - BeforeAll { - SuiteSetup - } - - AfterAll { - SuiteCleanup - } - - BeforeEach { - Set-Content "$script:PublishModuleBase\$script:PublishModuleName.psm1" -Value "function Get-$script:PublishModuleName { Get-Date }" - } - - AfterEach { - RemoveItem "$script:PSGalleryRepoPath\*" - RemoveItem "$script:ProgramFilesModulesPath\$script:PublishModuleName" - RemoveItem "$script:PublishModuleBase\*" - } - - # Purpose: Publish module that requires license acceptance - # - # Action: - # Update-ModuleManifest -RequireLicenseAcceptance - # Update-ModuleManifest -LicenseUri - # Add License.txt - # Publish-Module - # Expected Result: Update-ModuleManifest sets the RequireLicenseAcceptance flag. Publish-Module publishes the module - # - It "PublishModuleRequiresLicenseAcceptance" { - $version = "1.0" - New-ModuleManifest -Path "$script:PublishModuleBase\$script:PublishModuleName.psd1" -ModuleVersion $version -Description "$script:PublishModuleName module" -NestedModules "$script:PublishModuleName.psm1" - Update-ModuleManifest -Path "$script:PublishModuleBase\$script:PublishModuleName.psd1" -LicenseUri "http://$script:PublishModuleName.com/license" - Update-ModuleManifest -Path "$script:PublishModuleBase\$script:PublishModuleName.psd1" -RequireLicenseAcceptance - Set-Content "$script:PublishModuleBase\license.txt" -Value "LicenseTerms" - - Publish-Module -Path $script:PublishModuleBase -NuGetApiKey $script:ApiKey - $psgetItemInfo = Find-Module $script:PublishModuleName -RequiredVersion $version - $psgetItemInfo.AdditionalMetadata.requireLicenseAcceptance | should be "True" - $psgetItemInfo.PowerShellGetFormatVersion | should be $script:PSGetRequireLicenseAcceptanceFormatVersion - } - - # Purpose: Publish module without License.txt - # - # Action: - # Update-ModuleManifest -RequireLicenseAcceptance - # Update-ModuleManifest -LicenseUri - # Publish-Module - # Expected Result: It fails with LicenseTxtNotFound error - # - It "PublishModuleWithoutLicenseTxt" { - $version = "1.0" - New-ModuleManifest -Path "$script:PublishModuleBase\$script:PublishModuleName.psd1" -ModuleVersion $version -Description "$script:PublishModuleName module" -NestedModules "$script:PublishModuleName.psm1" - Update-ModuleManifest -Path "$script:PublishModuleBase\$script:PublishModuleName.psd1" -LicenseUri "http://$script:PublishModuleName.com/license" - Update-ModuleManifest -Path "$script:PublishModuleBase\$script:PublishModuleName.psd1" -RequireLicenseAcceptance - - AssertFullyQualifiedErrorIdEquals -scriptblock {Publish-Module -Path $script:PublishModuleBase -NuGetApiKey $script:ApiKey -WarningAction SilentlyContinue}` - -expectedFullyQualifiedErrorId 'LicenseTxtNotFound,Publish-PSArtifactUtility' - - } - - - # Purpose: Publish module without LicenseURI - # - # Action: - # Update-ModuleManifest -RequireLicenseAcceptance - # Add License.txt - # Publish-Module - # Expected Result: It fails with LicenseUriNotSpecified error - # - It "PublishModuleWithoutLicenseUri" { - $version = "1.0" - New-ModuleManifest -Path "$script:PublishModuleBase\$script:PublishModuleName.psd1" -ModuleVersion $version -Description "$script:PublishModuleName module" -NestedModules "$script:PublishModuleName.psm1" - Update-ModuleManifest -Path "$script:PublishModuleBase\$script:PublishModuleName.psd1" -RequireLicenseAcceptance - Set-Content "$script:PublishModuleBase\license.txt" -Value "LicenseTerms" - AssertFullyQualifiedErrorIdEquals -scriptblock {Publish-Module -Path $script:PublishModuleBase -NuGetApiKey $script:ApiKey -WarningAction SilentlyContinue}` - -expectedFullyQualifiedErrorId 'LicenseUriNotSpecified,Publish-PSArtifactUtility' - - } - - # Purpose: Publish module without setting requireLicenseAcceptance - # - # Action: - # Add LicenseUri - # Add License.txt - # Publish-Module - # Expected Result: Module is published with requirelicenseAcceptance set to False. - # - It "PublishModuleNoRequireLicenseAcceptance" { - $version = "1.0" - New-ModuleManifest -Path "$script:PublishModuleBase\$script:PublishModuleName.psd1" -ModuleVersion $version -Description "$script:PublishModuleName module" -NestedModules "$script:PublishModuleName.psm1" - Update-ModuleManifest -Path "$script:PublishModuleBase\$script:PublishModuleName.psd1" -LicenseUri "http://$script:PublishModuleName.com/license" - Set-Content "$script:PublishModuleBase\license.txt" -Value "LicenseTerms" - - Publish-Module -Path $script:PublishModuleBase -NuGetApiKey $script:ApiKey - $psgetItemInfo = Find-Module $script:PublishModuleName -RequiredVersion $version - $psgetItemInfo.AdditionalMetadata.requireLicenseAcceptance | should be "False" - } -} - -function InstallSuiteSetup { - Import-Module "$PSScriptRoot\PSGetTestUtils.psm1" -WarningAction SilentlyContinue - Import-Module "$PSScriptRoot\Asserts.psm1" -WarningAction SilentlyContinue - - $script:ProgramFilesModulesPath = Get-AllUsersModulesPath - $script:MyDocumentsModulesPath = Get-CurrentUserModulesPath - $script:PSGetLocalAppDataPath = Get-PSGetLocalAppDataPath - $script:TempPath = Get-TempPath - $null = New-Item -Path $script:MyDocumentsModulesPath -ItemType Directory -ErrorAction SilentlyContinue -WarningAction SilentlyContinue - #Bootstrap NuGet binaries - Install-NuGetBinaries - - $psgetModuleInfo = Import-Module PowerShellGet -Global -Force -Passthru - Import-LocalizedData script:LocalizedData -filename PSGet.Resource.psd1 -BaseDirectory $psgetModuleInfo.ModuleBase - - $script:moduleSourcesFilePath= Join-Path $script:PSGetLocalAppDataPath "PSRepositories.xml" - $script:moduleSourcesBackupFilePath = Join-Path $script:PSGetLocalAppDataPath "PSRepositories.xml_$(get-random)_backup" - if(Test-Path $script:moduleSourcesFilePath) - { - Rename-Item $script:moduleSourcesFilePath $script:moduleSourcesBackupFilePath -Force - } - - $Global:PSGallerySourceUri = '' - GetAndSet-PSGetTestGalleryDetails -SetPSGallery -PSGallerySourceUri ([REF]$Global:PSGallerySourceUri) -IsScriptSuite - - PSGetTestUtils\Uninstall-Module ModuleRequireLicenseAcceptance - Get-InstalledScript -Name ScriptRequireLicenseAcceptance -ErrorAction SilentlyContinue | Uninstall-Script -Force -} - -function InstallSuiteCleanup { - if(Test-Path $script:moduleSourcesBackupFilePath) - { - Move-Item $script:moduleSourcesBackupFilePath $script:moduleSourcesFilePath -Force - } - else - { - RemoveItem $script:moduleSourcesFilePath - } - - # Import the PowerShellGet provider to reload the repositories. - $null = Import-PackageProvider -Name PowerShellGet -Force -} - -Describe PowerShell.PSGet.PSGetRequireLicenseAcceptance.InstallSaveUpdate -Tags 'BVT','InnerLoop' { - - BeforeAll { - InstallSuiteSetup - } - - AfterAll { - InstallSuiteCleanup - } - - AfterEach { - Get-InstalledScript -Name ScriptRequireLicenseAcceptance -ErrorAction SilentlyContinue | Uninstall-Script -Force -ErrorAction SilentlyContinue - PSGetTestUtils\Uninstall-Module ModuleWithDependency - PSGetTestUtils\Uninstall-Module ModuleRequireLicenseAcceptance - } - - # Purpose: InstallModuleRequiringLicenseAcceptanceAndNoToPrompt - # - # Action: Install-Module ModuleRequireLicenseAcceptance - # - # Expected Result: module should not be installed after confirming NO - # - It "InstallModuleRequiringLicenseAcceptanceAndNoToPrompt" { - $outputPath = $script:TempPath - $guid = [system.guid]::newguid().tostring() - $outputFilePath = Join-Path $outputPath "$guid" - $runspace = CreateRunSpace $outputFilePath 1 - - # 2 is mapped to NO in ShouldProcess prompt - $Global:proxy.UI.ChoiceToMake=2 - $content = $null - - try - { - $result = ExecuteCommand $runspace 'Install-Module ModuleRequireLicenseAcceptance -Repository PSGallery' - } - finally - { - $fileName = "PromptForChoice-0.txt" - $path = join-path $outputFilePath $fileName - if(Test-Path $path) - { - $content = get-content $path - } - - CloseRunSpace $runspace - RemoveItem $outputFilePath - } - - $itemInfo = Find-Module ModuleRequireLicenseAcceptance -Repository PSGallery - - $installShouldProcessMessage = $script:LocalizedData.AcceptanceLicenseQuery -f ($itemInfo.Name) - Assert ($content -and ($content -match $installShouldProcessMessage)) "Install module confirm prompt is not working, Expected:$installShouldProcessMessage, Actual:$content" - - $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable - AssertNull $res "Install-Module should not install a module if Confirm is not accepted" - } ` - -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) - - # Purpose: InstallModuleRequiringLicenseAcceptanceAndYesToPrompt - # - # Action: Install-Module ModuleRequireLicenseAcceptance - # - # Expected Result: module should be installed after confirming YES - # - It "InstallModuleRequiringLicenseAcceptanceAndYesToPrompt" { - $outputPath = $script:TempPath - $guid = [system.guid]::newguid().tostring() - $outputFilePath = Join-Path $outputPath "$guid" - $runspace = CreateRunSpace $outputFilePath 1 - - # 0 is mapped to YES in ShouldProcess prompt - $Global:proxy.UI.ChoiceToMake=0 - $content = $null - - try - { - $result = ExecuteCommand $runspace 'Install-Module ModuleRequireLicenseAcceptance' - } - finally - { - $fileName = "PromptForChoice-0.txt" - $path = join-path $outputFilePath $fileName - if(Test-Path $path) - { - $content = get-content $path - } - - CloseRunSpace $runspace - RemoveItem $outputFilePath - } - - $itemInfo = Find-Module ModuleRequireLicenseAcceptance -Repository PSGallery - - $installShouldProcessMessage = $script:LocalizedData.AcceptanceLicenseQuery -f ($itemInfo.Name) - Assert ($content -and ($content -match $installShouldProcessMessage)) "Install module confirm prompt is not working, Expected:$installShouldProcessMessage, Actual:$content" - - $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable - Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleRequireLicenseAcceptance")) "Install-Module should install a module if Confirm is accepted" - } ` - -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) - - # Purpose: InstallModuleAcceptLicense - # - # Action: Install-Module ModuleRequireLicenseAcceptance -AcceptLicennse - # - # Expected Result: module is installed successfully - # - It "InstallModuleAcceptLicense" { - Install-Module ModuleRequireLicenseAcceptance -Repository PSGallery -AcceptLicense - $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable - Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleRequireLicenseAcceptance")) "Install-Module should install the module if -AcceptLicense is specified" - } - - - # Purpose: InstallModuleForce - # - # Action: Install-Module ModuleRequireLicenseAcceptance -Force - # - # Expected Result: module should fail to install with error ForceAcceptLicense - # - It "InstallModuleForce" { - AssertFullyQualifiedErrorIdEquals -scriptblock {Install-Module ModuleRequireLicenseAcceptance -Repository PSGallery -Force}` - -expectedFullyQualifiedErrorId 'ForceAcceptLicense,Install-Module' - } - - - # Purpose: InstallModuleWithDependencyAndYesToPrompt - # - # Action: Install-Module ModuleWithDependency - # - # Expected Result: User is prompted to accept license for dependant module. On yes, module is installed - # - It "InstallModuleWithDependencyAndYesToPrompt" { - $outputPath = $script:TempPath - $guid = [system.guid]::newguid().tostring() - $outputFilePath = Join-Path $outputPath "$guid" - $runspace = CreateRunSpace $outputFilePath 1 - - # 0 is mapped to YES in ShouldProcess prompt - $Global:proxy.UI.ChoiceToMake=0 - $content = $null - - try - { - $result = ExecuteCommand $runspace 'Install-Module ModuleWithDependency' - } - finally - { - $fileName = "PromptForChoice-0.txt" - $path = join-path $outputFilePath $fileName - if(Test-Path $path) - { - $content = get-content $path - } - - CloseRunSpace $runspace - RemoveItem $outputFilePath - } - - $itemInfo = Find-Module ModuleRequireLicenseAcceptance -Repository PSGallery - $installShouldProcessMessage = $script:LocalizedData.AcceptanceLicenseQuery -f ($itemInfo.Name) - Assert ($content -and ($content -match $installShouldProcessMessage)) "Install Module confirm prompt is not working, Expected:$installShouldProcessMessage, Actual:$content" - - $res = Get-Module ModuleWithDependency -ListAvailable - Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleWithDependency")) "Install-Module should install a module if Confirm is accepted" - - $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable - Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleRequireLicenseAcceptance")) "Install-Module should install a module if Confirm is accepted" - } ` - -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) - - # Purpose: InstallModuleWithDependencyAndNoToPrompt - # - # Action: Install-Module ModuleWithDependency - # - # Expected Result: User is prompted to accept license for dependant module. On No, neither of two modules is installed - # - It "InstallModuleWithDependencyAndNoToPrompt" { - $outputPath = $script:TempPath - $guid = [system.guid]::newguid().tostring() - $outputFilePath = Join-Path $outputPath "$guid" - $runspace = CreateRunSpace $outputFilePath 1 - - # 2 is mapped to NO in ShouldProcess prompt - $Global:proxy.UI.ChoiceToMake=2 - $content = $null - - try - { - $result = ExecuteCommand $runspace 'Install-Module ModuleWithDependency -Repository PSGallery' - } - finally - { - $fileName = "PromptForChoice-0.txt" - $path = join-path $outputFilePath $fileName - if(Test-Path $path) - { - $content = get-content $path - } - - CloseRunSpace $runspace - RemoveItem $outputFilePath - } - - $itemInfo = Find-Module ModuleRequireLicenseAcceptance -Repository PSGallery - - $installShouldProcessMessage = $script:LocalizedData.AcceptanceLicenseQuery -f ($itemInfo.Name) - Assert ($content -and ($content -match $installShouldProcessMessage)) "Install module confirm prompt is not working, Expected:$installShouldProcessMessage, Actual:$content" - - $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable - AssertNull $res "Install-Module should not install dependant module if Confirm is not accepted" - - $res = Get-Module ModuleWithDependency -ListAvailable - AssertNull $res "Install-Module should not install a module if Confirm is not accepted" - } ` - -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) - - # Purpose: InstallModuleWithDependencyAcceptLicense - # - # Action: Install-Module ModuleWithDependency -AcceptLicennse - # - # Expected Result: module is installed successfully - # - It "InstallModuleWithDependencyAcceptLicense" { - Install-Module ModuleWithDependency -AcceptLicense - - $res = Get-Module ModuleWithDependency -ListAvailable - Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleWithDependency")) "Install-Module should install the module if -AcceptLicense is specified" - - $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable - Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleRequireLicenseAcceptance")) "Install-Module should install the module if -AcceptLicense is specified" - } - - # Purpose: InstallScriptAndYesToPrompt - # - # Action: Install-Script ScriptRequireLicenseAcceptance - # - # Expected Result: Script and dependent module should be installed after confirming YES - # - It "InstallScriptAndYesToPrompt" { - $outputPath = $script:TempPath - $guid = [system.guid]::newguid().tostring() - $outputFilePath = Join-Path $outputPath "$guid" - $runspace = CreateRunSpace $outputFilePath 1 - - # 0 is mapped to YES in ShouldProcess prompt - $Global:proxy.UI.ChoiceToMake=0 - $content = $null - - try - { - $result = ExecuteCommand $runspace 'Install-Script ScriptRequireLicenseAcceptance' - } - finally - { - $fileName = "PromptForChoice-0.txt" - $path = join-path $outputFilePath $fileName - if(Test-Path $path) - { - $content = get-content $path - } - - CloseRunSpace $runspace - RemoveItem $outputFilePath - } - - $itemInfo = Find-Module ModuleRequireLicenseAcceptance -Repository PSGallery - $installShouldProcessMessage = $script:LocalizedData.AcceptanceLicenseQuery -f ($itemInfo.Name) - Assert ($content -and ($content -match $installShouldProcessMessage)) "Install script confirm prompt is not working, Expected:$installShouldProcessMessage, Actual:$content" - - $res = Get-InstalledScript ScriptRequireLicenseAcceptance - AssertEquals $res.Name "ScriptRequireLicenseAcceptance" "Install-Script failed to install $scriptName, $res" - - $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable - Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleRequireLicenseAcceptance")) "Install-Module should install a module if Confirm is accepted" - } ` - -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) - - - # Purpose: InstallScriptAndNoToPrompt - # - # Action: Install-Script ScriptRequireLicenseAcceptance - # - # Expected Result: Script and dependent module should NOT be installed after confirming NO - # - It "InstallScriptAndNoToPrompt" { - $outputPath = $script:TempPath - $guid = [system.guid]::newguid().tostring() - $outputFilePath = Join-Path $outputPath "$guid" - $runspace = CreateRunSpace $outputFilePath 1 - - # 2 is mapped to NO in ShouldProcess prompt - $Global:proxy.UI.ChoiceToMake=2 - $content = $null - - try - { - $result = ExecuteCommand $runspace 'Install-Script ScriptRequireLicenseAcceptance' - } - finally - { - $fileName = "PromptForChoice-0.txt" - $path = join-path $outputFilePath $fileName - if(Test-Path $path) - { - $content = get-content $path - } - - CloseRunSpace $runspace - RemoveItem $outputFilePath - } - - $itemInfo = Find-Module ModuleRequireLicenseAcceptance -Repository PSGallery - $installShouldProcessMessage = $script:LocalizedData.AcceptanceLicenseQuery -f ($itemInfo.Name) - Assert ($content -and ($content -match $installShouldProcessMessage)) "Install script confirm prompt is not working, Expected:$installShouldProcessMessage, Actual:$content" - - $res = Get-InstalledScript ScriptRequireLicenseAcceptance -ErrorAction SilentlyContinue - AssertNull $res "Script should not be installed" - - $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable - AssertNull $res "Dependant module should not be installed if Confirm is not accepted" - } ` - -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) - - - # Purpose: InstallScriptAcceptLicense - # - # Action: Install-Script ScriptRequireLicenseAcceptance -AcceptLicennse - # - # Expected Result: script and dependant module are installed successfully - # - It "InstallScriptAcceptLicense" { - Install-Script ScriptRequireLicenseAcceptance -AcceptLicense - - $res = Get-InstalledScript ScriptRequireLicenseAcceptance - AssertEquals $res.Name "ScriptRequireLicenseAcceptance" "Install-Script failed to install $scriptName, $res" - - $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable - Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleRequireLicenseAcceptance")) "Install-Module should install the module if -AcceptLicense is specified" - } - - # Purpose: SaveModuleRequiringLicenseAcceptanceAndNoToPrompt - # - # Action: Save-Module ModuleRequireLicenseAcceptance - # - # Expected Result: Module should not be saved after confirming NO - # - It "SaveModuleRequiringLicenseAcceptanceAndNoToPrompt" { - $outputPath = $script:TempPath - $guid = [system.guid]::newguid().tostring() - $outputFilePath = Join-Path $outputPath "$guid" - $runspace = CreateRunSpace $outputFilePath 1 - - # 2 is mapped to NO in ShouldProcess prompt - $Global:proxy.UI.ChoiceToMake=2 - $content = $null - - try - { - $result = ExecuteCommand $runspace "Save-Module ModuleRequireLicenseAcceptance -Path $script:MyDocumentsModulesPath -ErrorAction SilentlyContinue" - } - finally - { - $fileName = "PromptForChoice-0.txt" - $path = join-path $outputFilePath $fileName - if(Test-Path $path) - { - $content = get-content $path - } - - CloseRunSpace $runspace - RemoveItem $outputFilePath - } - - $itemInfo = Find-Module ModuleRequireLicenseAcceptance -Repository PSGallery - - $saveShouldProcessMessage = $script:LocalizedData.AcceptanceLicenseQuery -f ($itemInfo.Name) - Assert ($content -and ($content -match $saveShouldProcessMessage)) "Save module confirm prompt is not working, Expected:$installShouldProcessMessage, Actual:$content" - - $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable - AssertNull $res "Save-Module should not install a module if Confirm is not accepted" - } ` - -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) - - # Purpose: SaveModuleRequiringLicenseAcceptanceAndYesToPrompt - # - # Action: Save-Module ModuleRequireLicenseAcceptance - # - # Expected Result: module should be Saved after confirming YES - # - It "SaveModuleRequiringLicenseAcceptanceAndYesToPrompt" { - $outputPath = $script:TempPath - $guid = [system.guid]::newguid().tostring() - $outputFilePath = Join-Path $outputPath "$guid" - $runspace = CreateRunSpace $outputFilePath 1 - - # 0 is mapped to YES in ShouldProcess prompt - $Global:proxy.UI.ChoiceToMake=0 - $content = $null - - try - { - $result = ExecuteCommand $runspace "Save-Module ModuleRequireLicenseAcceptance -Path $script:MyDocumentsModulesPath" - } - finally - { - $fileName = "PromptForChoice-0.txt" - $path = join-path $outputFilePath $fileName - if(Test-Path $path) - { - $content = get-content $path - } - - CloseRunSpace $runspace - RemoveItem $outputFilePath - } - - $itemInfo = Find-Module ModuleRequireLicenseAcceptance -Repository PSGallery - - $saveShouldProcessMessage = $script:LocalizedData.AcceptanceLicenseQuery -f ($itemInfo.Name) - Assert ($content -and ($content -match $saveShouldProcessMessage)) "save module confirm prompt is not working, Expected:$installShouldProcessMessage, Actual:$content" - - $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable - Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleRequireLicenseAcceptance")) "save-Module should save a module if Confirm is accepted" - } ` - -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) - - # Purpose: SaveModuleAcceptLicense - # - # Action: Save-Module ModuleRequireLicenseAcceptance -AcceptLicennse - # - # Expected Result: module is saved successfully - # - It "SaveModuleAcceptLicense" { - Save-Module ModuleRequireLicenseAcceptance -Repository PSGallery -AcceptLicense -Path $script:MyDocumentsModulesPath - $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable - Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleRequireLicenseAcceptance")) "Install-Module should install the module if -AcceptLicense is specified" - } - - # Purpose: SaveModuleForce - # - # Action: Save-Module ModuleRequireLicenseAcceptance -Force - # - # Expected Result: module should fail to save with error ForceAcceptLicense - # - It "SaveModuleForce" { - AssertFullyQualifiedErrorIdEquals -scriptblock {Save-Module ModuleRequireLicenseAcceptance -Repository PSGallery -Force -Path $script:MyDocumentsModulesPath -WarningAction SilentlyContinue}` - -expectedFullyQualifiedErrorId 'ForceAcceptLicense,Install-Module' - } - - # Purpose: SaveModuleWithDependencyAndYesToPrompt - # - # Action: Save-Module ModuleWithDependency - # - # Expected Result: User is prompted to accept license for dependant module. On yes, module is Saved - # - It "SaveModuleWithDependencyAndYesToPrompt" { - $outputPath = $script:TempPath - $guid = [system.guid]::newguid().tostring() - $outputFilePath = Join-Path $outputPath "$guid" - $runspace = CreateRunSpace $outputFilePath 1 - - # 0 is mapped to YES in ShouldProcess prompt - $Global:proxy.UI.ChoiceToMake=0 - $content = $null - - try - { - $result = ExecuteCommand $runspace "Save-Module ModuleWithDependency -Path $script:MyDocumentsModulesPath" - } - finally - { - $fileName = "PromptForChoice-0.txt" - $path = join-path $outputFilePath $fileName - if(Test-Path $path) - { - $content = get-content $path - } - - CloseRunSpace $runspace - RemoveItem $outputFilePath - } - - $itemInfo = Find-Module ModuleRequireLicenseAcceptance -Repository PSGallery - $SaveShouldProcessMessage = $script:LocalizedData.AcceptanceLicenseQuery -f ($itemInfo.Name) - Assert ($content -and ($content -match $SaveShouldProcessMessage)) "Save Module confirm prompt is not working, Expected:$installShouldProcessMessage, Actual:$content" - - $res = Get-Module ModuleWithDependency -ListAvailable - Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleWithDependency")) "Save-Module should Save a module if Confirm is accepted" - - $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable - Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleRequireLicenseAcceptance")) "Save-Module should Save a module if Confirm is accepted" - } ` - -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) - - # Purpose: SaveModuleWithDependencyAndNoToPrompt - # - # Action: Save-Module ModuleWithDependency - # - # Expected Result: User is prompted to accept license for dependant module. On No, neither of two modules is Saved - # - It "SaveModuleWithDependencyAndNoToPrompt" { - $outputPath = $script:TempPath - $guid = [system.guid]::newguid().tostring() - $outputFilePath = Join-Path $outputPath "$guid" - $runspace = CreateRunSpace $outputFilePath 1 - - # 2 is mapped to NO in ShouldProcess prompt - $Global:proxy.UI.ChoiceToMake=2 - $content = $null - - try - { - $result = ExecuteCommand $runspace "Save-Module ModuleWithDependency -Path $script:MyDocumentsModulesPath -ErrorAction SilentlyContinue" - } - finally - { - $fileName = "PromptForChoice-0.txt" - $path = join-path $outputFilePath $fileName - if(Test-Path $path) - { - $content = get-content $path - } - - CloseRunSpace $runspace - RemoveItem $outputFilePath - } - - $itemInfo = Find-Module ModuleRequireLicenseAcceptance -Repository PSGallery - - $saveShouldProcessMessage = $script:LocalizedData.AcceptanceLicenseQuery -f ($itemInfo.Name) - Assert ($content -and ($content -match $saveShouldProcessMessage)) "Save module confirm prompt is not working, Expected:$installShouldProcessMessage, Actual:$content" - - $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable - AssertNull $res "Save-Module should not save dependant module if Confirm is not accepted" - - $res = Get-Module ModuleWithDependency -ListAvailable - AssertNull $res "Save-Module should not install a module if Confirm is not accepted" - } ` - -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) - - - # Purpose: SaveModuleWithDependencyAcceptLicense - # - # Action: Save-Module ModuleWithDependency -AcceptLicennse - # - # Expected Result: module is installed successfully - # - It "SaveModuleWithDependencyAcceptLicense" { - Save-Module ModuleWithDependency -AcceptLicense -Path $script:MyDocumentsModulesPath - - $res = Get-Module ModuleWithDependency -ListAvailable - Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleWithDependency")) "Install-Module should install the module if -AcceptLicense is specified" - - $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable - Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleRequireLicenseAcceptance")) "Install-Module should install the module if -AcceptLicense is specified" - } - - # Purpose: SaveScriptAndYesToPrompt - # - # Action: Save-Script ScriptRequireLicenseAcceptance - # - # Expected Result: Script and dependent module should be installed after confirming YES - # - It "SaveScriptAndYesToPrompt" { - $outputPath = $script:TempPath - $guid = [system.guid]::newguid().tostring() - $outputFilePath = Join-Path $outputPath "$guid" - $runspace = CreateRunSpace $outputFilePath 1 - - # 0 is mapped to YES in ShouldProcess prompt - $Global:proxy.UI.ChoiceToMake=0 - $content = $null - - try - { - $result = ExecuteCommand $runspace "Save-Script ScriptRequireLicenseAcceptance -Path $script:MyDocumentsModulesPath" - } - finally - { - $fileName = "PromptForChoice-0.txt" - $path = join-path $outputFilePath $fileName - if(Test-Path $path) - { - $content = get-content $path - } - - CloseRunSpace $runspace - RemoveItem $outputFilePath - } - - $itemInfo = Find-Module ModuleRequireLicenseAcceptance -Repository PSGallery - $SaveShouldProcessMessage = $script:LocalizedData.AcceptanceLicenseQuery -f ($itemInfo.Name) - Assert ($content -and ($content -match $SaveShouldProcessMessage)) "Save script confirm prompt is not working, Expected:$installShouldProcessMessage, Actual:$content" - - - - if(-not (Test-Path -Path "$script:MyDocumentsModulesPath\ScriptRequireLicenseAcceptance.ps1" -PathType Leaf)) - { - Assert $false "Save-Script should save script $ScriptName" - } - - $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable - Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleRequireLicenseAcceptance")) "Save-Module should save a module if Confirm is accepted" - } ` - -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) - - # Purpose: SaveScriptAcceptLicense - # - # Action: Save-Script ScriptRequireLicenseAcceptance -AcceptLicennse - # - # Expected Result: script and dependant module are Saved successfully - # - It "SaveScriptAcceptLicense" { - Save-Script ScriptRequireLicenseAcceptance -AcceptLicense -Path $script:MyDocumentsModulesPath - - if(-not (Test-Path -Path "$script:MyDocumentsModulesPath\ScriptRequireLicenseAcceptance.ps1" -PathType Leaf)) - { - Assert $false "Save-Script should save script $ScriptName" - } - - $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable - Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleRequireLicenseAcceptance")) "Save-Module should Save the module if -AcceptLicense is specified" - } - - - # Purpose: UpdateModuleRequiringLicenseAcceptanceAndNoToPrompt - # - # Action: Update-Module ModuleRequireLicenseAcceptance - # - # Expected Result: Module should not be updated after confirming NO - # - It "UpdateModuleRequiringLicenseAcceptanceAndNoToPrompt" { - - Install-module ModuleRequireLicenseAcceptance -RequiredVersion 1.0 -AcceptLicense -Force - - $outputPath = $script:TempPath - $guid = [system.guid]::newguid().tostring() - $outputFilePath = Join-Path $outputPath "$guid" - $runspace = CreateRunSpace $outputFilePath 1 - - # 2 is mapped to NO in ShouldProcess prompt - $Global:proxy.UI.ChoiceToMake=2 - $content = $null - - try - { - $result = ExecuteCommand $runspace 'Update-Module ModuleRequireLicenseAcceptance' - } - finally - { - $fileName = "PromptForChoice-0.txt" - $path = join-path $outputFilePath $fileName - if(Test-Path $path) - { - $content = get-content $path - } - - CloseRunSpace $runspace - RemoveItem $outputFilePath - } - - $itemInfo = Find-Module ModuleRequireLicenseAcceptance -Repository PSGallery - - $updateShouldProcessMessage = $script:LocalizedData.AcceptanceLicenseQuery -f ($itemInfo.Name) - Assert ($content -and ($content -match $updateShouldProcessMessage)) "Update module confirm prompt is not working, Expected:$updateShouldProcessMessage, Actual:$content" - - - - $res = Get-Module ModuleRequireLicenseAcceptance -ListAvailable - Assert (($res.Count -eq 1) -and ($res.Name -eq "ModuleRequireLicenseAcceptance") -and ($res.Version -eq [Version]"1.0")) "Update-Module should not update the module if confirm is declined" - } ` - -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) - - - # Purpose: UpdateModuleRequiringLicenseAcceptanceAndYesToPrompt - # - # Action: Update-Module ModuleRequireLicenseAcceptance - # - # Expected Result: Module should be Updated after confirming YES - # - It "UpdateModuleRequiringLicenseAcceptanceAndYesToPrompt" { - - Install-module ModuleRequireLicenseAcceptance -RequiredVersion 1.0 -AcceptLicense -Force - - $outputPath = $script:TempPath - $guid = [system.guid]::newguid().tostring() - $outputFilePath = Join-Path $outputPath "$guid" - $runspace = CreateRunSpace $outputFilePath 1 - - # 0 is mapped to YES in ShouldProcess prompt - $Global:proxy.UI.ChoiceToMake=0 - $content = $null - - try - { - $result = ExecuteCommand $runspace 'Update-Module ModuleRequireLicenseAcceptance' - } - finally - { - $fileName = "PromptForChoice-0.txt" - $path = join-path $outputFilePath $fileName - if(Test-Path $path) - { - $content = get-content $path - } - - CloseRunSpace $runspace - RemoveItem $outputFilePath - } - - $itemInfo = Find-Module ModuleRequireLicenseAcceptance -Repository PSGallery - - $UpdateShouldProcessMessage = $script:LocalizedData.AcceptanceLicenseQuery -f ($itemInfo.Name) - Assert ($content -and ($content -match $UpdateShouldProcessMessage)) "Update module confirm prompt is not working, Expected:$UpdateShouldProcessMessage, Actual:$content" - - $res = Get-InstalledModule ModuleRequireLicenseAcceptance -RequiredVersion 2.0 - AssertNotNull $res "Update-Module should Update a module if Confirm is accepted" - } ` - -Skip:$(($PSEdition -eq 'Core') -or ([System.Environment]::OSVersion.Version -lt "6.2.9200.0") -or ($PSCulture -ne 'en-US')) - - - # Purpose: UpdateModuleAcceptLicnese - # - # Action: Update-Module ModuleRequireLicenseAcceptance -AcceptLicennse - # - # Expected Result: module is Updated successfully - # - It "UpdateModuleAcceptLicnese" { - Install-module ModuleRequireLicenseAcceptance -RequiredVersion 1.0 -AcceptLicense -Force - Update-Module ModuleRequireLicenseAcceptance -AcceptLicense - $res = Get-InstalledModule ModuleRequireLicenseAcceptance -RequiredVersion 2.0 - AssertNotNull $res "Update-Module should Update a module" - } - - # Purpose: UpdateModuleForce - # - # Action: Update-Module ModuleRequireLicenseAcceptance -Force - # - # Expected Result: module should fail to Update with error ForceAcceptLicense - # - It "UpdateModuleForce" { - Install-module ModuleRequireLicenseAcceptance -RequiredVersion 1.0 -AcceptLicense -Force - AssertFullyQualifiedErrorIdEquals -scriptblock {Update-Module ModuleRequireLicenseAcceptance -Force}` - -expectedFullyQualifiedErrorId 'ForceAcceptLicense,Update-Module' - } - } From 459695a5cd0dfc1f83520aebf8f2a456021325ea Mon Sep 17 00:00:00 2001 From: benny1007 <32260961+Benny1007@users.noreply.github.com> Date: Thu, 2 May 2019 23:30:34 +0800 Subject: [PATCH 06/19] WIP: localdev publishing (#462) * facilitate easier local development * update readme file --- .vscode/tasks.json | 97 ++++++++++++++++++++++++++++++++++++ README.md | 46 ++++++++++++----- imgs/readme-getmodule-1.png | Bin 0 -> 43023 bytes tools/build.psm1 | 38 +++++++++++++- 4 files changed, 166 insertions(+), 15 deletions(-) create mode 100644 .vscode/tasks.json create mode 100644 imgs/readme-getmodule-1.png diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000..3f54a1ce --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,97 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "Build and Import Module", + "command": "pwsh", + "type": "shell", + "windows": { + "command": "c:\\windows\\system32\\WindowsPowerShell\\v1.0\\powershell.exe" + }, + "args": [ + "-command", + "Import-Module ${workspaceFolder}\\tools\\build.psm1;", + "Install-DevelopmentModule", + ], + "problemMatcher": [], + "group": { + "kind": "build", + "isDefault": true + }, + "presentation": { + "echo": true, + "reveal": "always", + "focus": true, + "panel": "shared", + "showReuseMessage": true, + "clear": false, + } + }, + { + "label": "Install Dependencies", + "command": "pwsh", + "windows": { + "command": "c:\\windows\\system32\\WindowsPowerShell\\v1.0\\powershell.exe" + }, + "args": [ + "-command", + "Import-Module ${workspaceFolder}\\tools\\build.psm1;", + "Install-Dependencies" + ], + "problemMatcher": [], + "presentation": { + "echo": true, + "reveal": "always", + "focus": true, + "panel": "shared", + "showReuseMessage": true, + "clear": false, + } + }, + { + "label": "Remove Development Module", + "command": "pwsh", + "windows": { + "command": "c:\\windows\\system32\\WindowsPowerShell\\v1.0\\powershell.exe" + }, + "args": [ + "-command", + "Import-Module ${workspaceFolder}\\tools\\build.psm1;", + "Uninstall-DevelopmentModule" + ], + "problemMatcher": [], + "presentation": { + "echo": true, + "reveal": "always", + "focus": true, + "panel": "shared", + "showReuseMessage": true, + "clear": false, + } + }, + { + "label": "Run Full Test Suite", + "command": "pwsh", + "windows": { + "command": "c:\\windows\\system32\\WindowsPowerShell\\v1.0\\powershell.exe" + }, + "args": [ + "-command", + "Import-Module ${workspaceFolder}\\tools\\build.psm1;", + "Install-Dependencies;", + "Invoke-PowerShellGetTest" + ], + "problemMatcher": [], + "presentation": { + "echo": true, + "reveal": "always", + "focus": true, + "panel": "shared", + "showReuseMessage": true, + "clear": false, + } + } + ] +} diff --git a/README.md b/README.md index 0f945216..72914752 100644 --- a/README.md +++ b/README.md @@ -106,29 +106,49 @@ Import-Module src/PowerShellGet ``` +Local Development +================= +### Visual Studio Code:- +1. Open VSCode choosing "Run as Administrator" +2. Select Terminal>Run Task>Install Dependencies +3. Select Terminal>Run Task>Build and Import Module + +for subsequent changes you can just run 'Build and Import Module' or press ctrl + shift + B + +### Standard PowerShell:- +1. Open an administrative PowerShell prompt +2. Run the following commands +```PowerShell +Import-Module "$ClonePath\tools\build.psm1" +Install-Dependencies +Install-DevelopmentModule +``` + +This will take the published module from ./dist and install it into the powershell module path under the current version of PowerShellGet apending 9999 to the version number. + +An explicit or implicit (such as when the test suite is invoked) import of the PowerShell get module will ensure the module version under development gets loaded. + +It is therefore easy to see with ```Get Module``` that the version under development is loaded, like this:- + +![alt text](./imgs/readme-getmodule-1.png "") + +To remove this module and revert to the production PowerShellGallery published version, simply remove the folder from the module path. (if running VSCode select Terminal>Run Task>Remove Development Module). + Running Tests ============= +### VSCode +You can run the test task Terminal>Run Task>Run Full Test Suite + +### Non VSCode + Pester-based PowerShellGet Tests are located in `/PowerShellGet/Tests` folder. Run following commands in PowerShell Console with Administrator privileges. ```powershell Import-Module "$ClonePath\tools\build.psm1" - Install-Dependencies - -# Option 1: Execute the following, replacing $ClonePath, when testing PowerShellGet module changes under $ClonePath. -# $env:PSModulePath = "$ClonePath\src;$env:PSModulePath" - -# Option 2: Execute the following commands to run tests with the merged PSModule.psm1 -<# -Update-ModuleManifestFunctions -Publish-ModuleArtifacts -Install-PublishedModule -#> - -# Run tests Invoke-PowerShellGetTest ``` diff --git a/imgs/readme-getmodule-1.png b/imgs/readme-getmodule-1.png new file mode 100644 index 0000000000000000000000000000000000000000..bc2718b8dee3b815b318dd264e6c715eb44bdb6b GIT binary patch literal 43023 zcmZsiWl$VXwDxiL;O>Or?(Pl?1a}RKFTOYgU7X+^AR(~9-Q6L$y9alNoBzG_etW0R zbWQ!v)6;!wYPzesPe*I2D`29LqQStxU@9rf0$^a^l>R+Gqrm?wm3l9s=(jxrYx0D=R^!7*gU zu`0m<(GYW45rgV!h?QxW{~3UW3q&IXqLBvE0K#bub7+7iG@yEBApo*_UphDp^(n8YG(pJ*S z%F8fndPDwt?Y7(&0d>a3Cl= z91;#G2~UNFm(+(tC&JrtAY952X#hkT2r-m~7y=-MR*-Nm2$UG|&(%Hw8Te-hsQ{r= zpj9eJITZv-4F{(}AgMXbsX5Tp37XV(lpGLqPHIk04m1Z^p93ApsjtszpU4@&$r<=p zuIJ3J=d7QX7y|yqQvzZx0V$V&tV+PjC16kql(+;+1Lcy20>h!{D z1Iz~#B?lAr2lM~r|Jp=3I9NZwzrUB3zOM)04?ynMq4(z~_vh{R=l^OG-@nhluQR{D zzr&T1p8WeIP+b)bKrk>^egECC-&nB7{y}69B{ezZ9RxHC222BsKZO5_e&%)jLi?ba}7ukN~KZg8&^*!CKY+!ER!;b%-Ovc5@$;R0O=58#l^B+U{Pp0$5 z!_fxj=h-w93=B1llB|@DPtHj@rjO2Cu0-G@#f0ivCTjFihR(I{0OBy26*aLcDI#t- zX|`6XY!Eath69CJDrMt$Rk-;}{kP@B{@^AJYU{8jqwza~9c#!b#=SwdtOo-}(UK~` zM`)9{(UeUdo5aWWm&xY)yhf3*)1ZaZw^keO%uMi^(8hJZW6t?wUOKpvJK)jt@z$m- z_1zhXz4I-yjh*i3>Uh-GM1Fd2A^o}qQaoD8abQEkOejoDih-GYznS!I8vjozXhxXq z=Nx!ao$d0rJZ|>99A^e*z1tZ5SB+|KRC?M83eXv1D=3w)cA*WH4qq2aL>dN|l zbx~WGqXEif_sjRXzrAt^n`SPK++41gt=a4$#jzahb7mcH9@{B12XJEANi!UQ*>p!i z-u^8QOb>$+e1}YmJ*|zYB#KWDY1?^6wNqu@@R92VnlCAf2Xy%r1M=@`Q__GtJF?pk zM9)-N56&wG8^-~A?8YW1c5#DTA+bRvZ++HQ1j9tJ{ifWULDfM!OPx+ALB~u74R@3Y zxl~bD0XsKjw@ICc55;>-?*{cIf&J~O^qA}Z*W(HO>Z_1Koq+EaYq1*v*1~tOt?Gl8 z2N3>1nx`r670c?$qH1)mUPHLJ*q~Oor`1NREzzk(UU3Q$;O+yfpQZ5K(q%#=n2f6Z z^3UZ*W*AUBgYuTmM(@PkQ^yUt9k8zZPKT+6{i2Y^HgnnLR!~JmkgGBV}TK80Bk$eP? zk-E1y|7*f{wRia&&ac-G;7mnfMa$yuMHDxs`Up>sKq7FM#)9nptXk((#AP+`Zn>!8 z$ou@`7nI-r;3uL56~*Q1FHfu6-RKfoVx2F2WXGi&?YE~OOeXP;owOD8&T4z--RDtx z&SbcdqR_>!g^%czG>V35i8m8PMFh4s8$95~*bR}Wgh}u1yerWG!xL4Xous1#0W1l8 zp4LBx@Jjb>0D%Atva`BC9y_h6n#Jb%Xg{k&9Ps4?pBzE8cmASwY6s5u_Z?&njm}oK zhtowC-;JELc%`=I)5Wqiev&hACO1F|2JY<>@`MGFP?ex2NIGN&t8&7Wf&m~^m zw!Q|92|t`;YHzeLH8niOHUIcwC6U$1d?){;5vcu=k`PO3#=OwEa(UD^_O{n!h9^C9 z&}kPgMwlGWha+f_@3E!ucFHu-nDb`+ZTPs^1+!y!3O?R!wkjysG2CiCI5N9&}u{Qm9`K^PxRSc{lv`eqo?C(;n8Hi=^t0W zrx_;pIRdl5*GMy@WY>(F#puPMUu0Be?QZ=AUyCEFHT-%GExpL2F~#s&A1qgx)0Hvi&ss-D%O3vavcH z5@h^x*6khZ@b~=ju=UjLZB=%nUFU-7Y3D>&Vb&9)?Z|Gl&LcZS2cF45zxyYa`ym(_OX zr`4WDbtkcKk+%3FvsFr-y_T0Jz`w}i|BZo5kz5h#eJw7c-F}VN8_;&aV5gT@h0={? z7O%jm-h6gix;hX`BaV?qz7Q_@Z>Co?{w?04zz#RzJ4>Szs&t8$qfvC^NsgW~#=Gf8 zD9=6o-IJ~dTj}+PBjj;t7_s;aRV5rs>z!k({P`W#gZ;dYhZC{fR>~nx;o-&DMzwsi>kq4*?GKzZ zfhXOIo#|HeYm{wHPaElKn;rjRG+Y%)8&D5;c0a!>>BRUqnmp)xvr)b!gtrI;j+2(X z&Q&nnV*Z%i2+5sze45D*1YyOeu(xr6hikfHgZAo$ky*~-+wJwQR`-RxSH1k6h>jxJ zUv!U-7DeP#KL2%DB@k)!9cJ76VMeR?x9Q@wEel-wRx?iA+W!P}HgJ1d+n$*ra_f7& ztZ3v)ZmBMRMk8qh42BOkNIw2ZC%f5$}@1dmcMhE$(oClkowyZx5gnTflj;p;{-Z%Z; z^53}=@mn6NE9b-`o*M?8{Z9%I6L_|MQ;OomBv0M79+ygBD_p=FZrd+}e3&^v-eaVA z9wR1IGebG=Wj}!PqRQX8INH`-^oDB$MC)#5Er4~8F0(@+WJ5= zrbf^de2iH>7!aLX;;S};tvD5o2<`tr8^kdZBBc9i-NTh5MWR5D5q_} zQ%@eh@x~inc(rp*L+5eV(PG(ayU)X)%Sf%W{Mpeg4dIY?%iVWb){vdf3kKw$#5_GN zkI(NcB^*8hH6EH{{SJQh+Y&kpdkaJz4`|L~KCc2bS0$a0vdRsS$E#zB`=^vubXO9k zcf?8wC3=&xx^moe(xiiqO5y^xoP>DAC;?k^8=2cvy&6OE?4iA*|{mCz$*x2sr>;`8n<-V*9YS4^tIf!0gz-+TMk%O=$oIh_2AvL75Z_!Mm27P*cuz5`BD#et==%Nb z>W6qQ*H)0d|E9#w%0my6ZAXKl{aVl~u=2Sw$i&uTCo2Wc(RBKJbKeKfCGOu1F zc=n0`1!Qq0^O};#1m+aRJN*Qo2IQV5FD2qu*~D(Lbfuro-*OBh{TR{4D5P-qQ?GYf zk&L5TK?wPKp(_cTJSy_fpiio+-AOqog9exMmmw{t04np zeSE)DS}43?^vMvOIDH9I5H}r4Di|*l~EG%Y?#ON1V)+t?3N^!9(Y3*Y!#AE^g_ z%hDO}e(-*E{hcJ?eFZ$}e^KW*zVY&qDG*d_dbx}&5wPFeRX_Qk>y>)40@dX51vI&S zv6?_M>3`a6C;pK1H}G%$!Q1{q|3X_cqVeUH?MX_WUq9?tePsUgr%D*z@^eq!Re{H0OJsF7_6f`E+|fo&S`n(0OPWjM`f%+$ z;NYw`WN_nhTeQCk=WH#;uA@O7v9hvzZBLtHCw{+7Pj_$qyJ?Tm8!&(_ z^5-@z#l*MEmow+gaifI)o<(_$^K1fLp&di%IHEo@?-f=fl3C>EnO>I-^{coGyb@4R zQ5FN)SQx8LrMFfRK%e+B@AJ{aQc)$Ibs`!+saC1lV%({Wz%(QP?_mV&J1Gi2?MxMY ztNCU8yp?lM{k9eVrX`=nRK)+m;5OzvD9>+i`QF(lkZ0n0IjfRN zO|LWbxwRK~@yI5q)8mGRQ2Bm!v4tIIQjs-g;Zo-h#kPjdz1X}VqOcn^yX%n{=ciL$ zuyQb)b$abx-S*S74tN%0seffOYWrft>Xai~|+QbU)r`Jbu%y}_G68c~4DD|l{zjU`#bU4r3g(gKs&R-Gl zx2X?~6{fBye~pYS=uN&{e%`L11)8p?ZoAxL3b1B`CGBP(wQmoikBRc#cYJraek*a@ z-0J!PA)gq$rrzVmrQVgA5Kdy3uplL^Dl)-y^zUzDFIiq$53qA`6j|+a+ z6=i5INq7#-`Q;W3v3&KyKDsk9CfSDfKNBG9fA7tpd)^CVGT>EHW4|9iP7PM$&U*qZ zn)4wqT*-;i#oUO5>g)sRPzHkyexlKM$u%5K^6xafEib;q8U;S+MY*Ja1vNslT%~E* zxHP<_tfjXlhkBvIug)j0pn?1s!g;%r^&*n*6yGbr>(AKMo9ocsvh=r;-v0YH*7K|b zv(KGxfx|gel(!T9r?5Qufp2r7mO!ihBNnPBl!kfp)jcs!-q&U9dE@J+ckPqFQ{DTW zP7};kJ<)fbMzU2f?_`!WceN8Fze*$YZ4JF`6lgyG#NZ0W4zu@F+Bd9RiBlA#H~STc zd=^v)vg>S=-1x;GSBD=+IIBE3+Sa6@iUwtXr5wBQ1JRX>QHTVWw`-SSJ-3-+_LP^a zZ&^s(5UQ^q&5H^W-<+IWi{p8Kl_m}N_!o{#F(5 zYvwyH5_MsE%Ti%);?(Ch6{o`A1`~Nmyme2$@7b^Gtq(s>%u9$EUOjXMT)d6?9KJkA zykBeOb6+?6@$lx~KS^|+^Vr>Q)++=^=05I_o?hN>h{jkIzu%7DpFe*g$+*A154teM z^m_@z4t#vWL&{!8NOX{kJknUY|aZ!?2#C#h>l)MzCC?QK>Daq z_Iyrl9I_imr_Gl2S*Tjjz^uHi@tBUTH3aAqe3A0~cxu>>(`v>xvevD9+n+f0{wE+r z`+KX@UH4B)Oj-qH1rPcb!%NMjm7{(fj?VTkU6q4ox1_1Mz4<@!UFp}SF#div*nt{xyv7 z^_a5co6!S_0zf!cb?gJ9pwo9<6rnQxy2RcIE<`p^He13M zWP4F{Ys+(Pr1It8l)RY&`EHD;y1Bg;q+S zFS!VwS5X;1FO%AOi57#`S9zq1u7wibm(f4=Fr?7n%Hs>+Q5O6`A-3HE6-8-|u>O@9 z>(`JpPf7N6RNU?h|15g%y=6T`OegpJeK={D^@u_AW)BYVm7KzR3yGdcB6Z@Hm_j8>$Bp1%I>hjh7BU zt|iR6w}`721dnUG1YZ2|>jz4_pJr2u78vTT-fv;=`yV|1=x$rsc-gc;uzS0B6$on8 zZN9gOItxH1b6W?SZa0~}Z}#%R(0-IV-%b1~s6*c?pZv9007Ps#XrDr)Q&uCf{xYO_-NK4)KTg+`p_#-Mw< zAIo!PJ@G}RefPH2_X9};>WsH;AyN7Kwej2s8o~O#*zJ21RcoED9|T^k!cR(o$G3jW zv52oi@}4q{?-%6Tn`}#rm~_|pgiGSGuWyE5;!5)n4M#uem;Kn0D;n=8L;-9KVOtT=7^*KSw;D1$G?= zzLY$R8(;O>aaj(X-1AjJkznqf6FN`&#g%#$pX4ZE%-%1My*KVxI;)=5oOPC#`BRkS z5L6eXWIHe{X_?op3_qoGsKwl*W0DUIeC-M$D7oy82=9~)#EZ#`kA4}Jg2@<~;n`faM0>3QzD$MBKuIsrxRH-6PN}y8)kr06uw71&s+dnnkr%SwE zCgihJV^$!_H@_kj_o0Ttd@tDr3v;qr0{tlB_)JXj;P-O19=Yu+wsb4&wi#c|ZoiOIH^We&^@HqK@pH%cQ?83%lp}=tAHFrsqDgkzL0fk@S*0DIW>9Fx@T%U;IQ2fImw40FEEpFtY zAPax~JH_^HkCZBlHeafjn+uM7-GlbW`=Iw3ZgSsF--jQ-p)bgqcH$Zhq+)^iZ8-n4d+M@Ed| zzPcuCpp+KUdDjsOrbBNY+OQJq-S+^Z5WQN6*kxecho1h*_UALQE8g3zR;s3z$Pbmx z&u2n)jNEsT3+BNS;7ufMPmkWUH{g|yYwsHR)m4|O@mUC>pnd1o8M1SA<@ft7Ge}XkFJko@Cl{v~aj8XQ^w!8ldnLN{x@ivGINd5{2CFVsP$&fsV(B~= zhajq>zt-qSGwj`26AXBczC$15JOw&Jv66iE$UH9kK}sn|6hN=ZMXJ8v07MTkk|o1w z5X|)PluwD*CQ5Yh?;p_-wF0IzQ+4GzDX>&Z*4tZ|9|w}RR64C^Q7h2&(`;ZAe@S_|IqW6)~85)L&Yw!giihUTUfAvl?qhuduH5pI0eI~x@I#;o};-ej_n{*&b0B#uvpG0&DeW%rjNEQ{% z(AfxUk!1+2d#E4;HWiK*)~e`|o>+O6rd#&2u*i6Bq_vtBRgR%_+|sUHJsnB`hTE54 z0C8rEc53*uLCtFR->;( zHi2BuDAu66}?SL z%rd2wNCbFC%Ze&aX0rYS2<| zFz`9tD8U=2#)$@w+t%b@f(c~Liy$T z-<-|NL8I@PFaF}pZ*15_+jB|gi=n~9m&{bchc4m|Y!J)B;` zeM*Gdk-Id)4b}eGPqjeJ3l=s&$rWxw!M)v*ueLfDAV(_3$`nl^zMOQ z?J6mZUO2D#MdYPMWoiJZq!w73gD$=(SXIdyAzBPVeZnAD|C1?$ba$FeVh8jG110K@ zsv{md(KxFLjT_5wur;C-0{tW2PJ}=+f~6MwVLA*6BSC@Fv-h4tnug^k6^xH)$ivyo zpr|v+)P1~ZTChAUb;aqjytzCdfUOO_imL~P6&7}A#+E$XGAc|j%!d)CMLoqRD;^qfXj(9k8rRvOYJ;{0;r?J#v+vMQR!YDL{wENU5BgzUnPgGrSf& zV;>BB>6%sl*Hg&?=PzW+On4a?Jg6C!Z$){?9xi(K+99LT=T(c0dPRkV*4$EMxenugjiKUxv_$}Fi#1=YSv) zQTue5_Vn1*eGHXH!XRB_>OhcH8 z$#A;8jqG9>`_#^h@d&!UGNLgvY7YiN0rc2BOD#&VY#1Gf^TI;35y1~pO3JXQFBIjI z=+&d2Ax9|Z=d}@e=Z6ziyK|=7`zsTGStanUx4p+zUut8s#EBpH-k(w)$NK zIGf-0NP`kFy7bjVG~uiVoLqisGsBy|((91_j-SE*L31!q1iu1+FR3`Eg?Z86Q^# z4vY&|tdO@X17-U+6Iu%7oy&!)$H!A$juO(i0Jw7>-RafR%m>J^$Tl5ao{bZ!o4Hx` zzPfTLGMgO^eiI%YEoX|g=pYlklyK#{O)>smVDJ7bR%xQ#FyAg*LF@l~^<6f?=M6qrKdA2&2Q)G@N z*4be8Sy{Yg>;lsy%2yRo*hYV-=Zjc>6f_bk@v&kQr75Jwtwa2X76_4pz-?|1E^?;{ zF{smFoynFs1z^3LURllAJi^Wk^W(cWjii$Z-`H|w!`FU33fS9yBxSyT2xuba-=8Q* zD?gv!>|yBA?Qj)>%X@h_z8Y;$JWkXfNXg__q#$!JXx_*ro^z)UvsOzn8;KA7{VF%? zl=KI`Veyj~_k)t#uMQ-7xxZY=c_;Lc`mZ-!SE)IFtM)aI)d@m)+ZkR%GZt7}ZG!h!)>B3lZX> zRQ+mY;r#B+W4y@Y%Kb1`H+gf|HC%|HO3kbM5K<}#KySWD4Y2fK&`jU`w2d2~KWpFJ z_lYT?KrTk{kc+_sm2D^FaD<&|_WvFD8e6k=-pH9i$3UXA2a)n0|A-9pz+_q}8K z&yxMe9N1bg@{KE!VmH(GR|gPhm=C$#cku#mKlDiq%e~t@`Dm=j&a7!-G_|>(b5F9e z8*(S&1wjA|mYWdGAD86JE1Sxj--eN`OGCI@ep#3+tyPs0sE>{0e$+}Hh)DsTBQql< zFDsrm{5I2?Pl{yKMaFd#y4@_bGQ2WRY(k%$Fd2d55sp_N8IwS@vdv%-lV};7EcqSZ z+HB<&I$O^&E_ua~e=;^InF$ob8WYXOrt#+uGUoXz4voPdKYc#!a5x~;&->kUGpDCM z?|rinG5Yt3-~wf95FuW4j;7JU)*F?}mdBC~8P)kt$@j7`n6CB{7JS2jG|D5hTvj^y za!Bm%7zSVaSA)Oqcb|Hhw}z3Xb~Y2xHSBI46BkU-EG*9Kb<~Ql=Z!gE`C$dl z(x`$A&SCElB)1g;PSlGhU@rS$qidytEJB5qratG5pck$JNc(8MmI&bUl=w+Hj~2Do z+dmN>D3`=BuUJ59G22_9u|9$xumt~hM?va(_xm?SDNyM{|8U{+Z~&~%rsK+25`PQ- z^Sf^Cei(SzGDWAq`BNQVMVa~v`OiC^6n)Ou8;5!`aNKYw;yZTNUCQPLd!bHt?>%$# zKYs4nP&YEQ4Wb-4L>BZmgOFhawVj(#Hd_SyGG7f?^0bKB9L`Nnv#VWB97H}SlC}Tx zRXBTCjlXOMqe?^}%WbbVP;-QOwD5GK(tGr!a*5NiXbCsLR2nJOh= zxnxt<(d0euvq+q#4rMd<9fif;F3K$H|5|&TOTzq~(U2c}&8jt_%A`+7EW>KiJ@Nh} z&M_rG_TQd56(Y}a ze1dA)7sNg$xtL7M2M78EE4FA1^}q!KqPVlz&GplkNbi524JUAbiU3Tw6b09IvLfD( zrKLnNOc&?skoIwKzc)`dR6`;i=U1=wdG05N$xk zHSbRsB{b%txZ2~OmnyC?E=_1fL7tJaKF@~5Dyy+fr5*ufJB`_vX=*h=J7Xs*cj}N& zR?OBTLZBO~K$FQ*Khxz2$OY&*xY|W3axfn0hG(_Rj%rn()Zc#aqR|ruMAAw=EPI?J?lGmFR&IOiiWTidPB#K`%7c5d*+MPKv_xjDE7WaOsa!k>4H5kb>;cYS?*7z&d z^EhkA4|Nb{=})3m1$meQodInf=|}L&>u2VOMWOS_*Ejqj#%{_FpCl@pVKz}S=!Ac;27u5Y%VgWh!49EQLJan>Fb>8`)ckn1uNaO< z)+w5~GZiS^mjvD6VVnuCMa75ng@X+qxef6VX-SPZ)UYsEN5~DQTUt!k?elU@$zEA` z;kjc{vQ6q5`__xkYAF!%dvDJV$@CM__L&UAJp*Ye1*Y_`@h)0NIk%m|PC+D^>JG4qP?W}sYv9}XlRPOZSIO;;I0_n; zz4UkOr;&gJ4xZhDqyN%zmC>-XvBA5?s3EQ7MH_zvG}%qFz&AKt(XGHXhVJ`E%GY_0 z`SK-dayx!&yWkq8njU$$WVAj5E3A^f#Uzd1KB2OHcBq;I(Yia^H`IMgREVObleU_Y zili;!*Gsxz$~sJg#4a}|L)xs-b@8&S^wPv4R779UN^zDu&2h6eYnnn)@f>Kys|Ygd z@>ANbi55ruehzUVrUggK(gh63^!Xfpq^P~U&Xxj|hO-v=ZIh(_O8flB@hiexaaTY8 z6fhsJYU5vKX)2~=wS)F!$?s!a-|9%fG*0$Z+DmXTqiqm1uO(Oc+D)jxXm=isvq}@R zq0fbSTZuo#o+0m(g|Pz>oYAPZm5htVMxEYC`CIf?1S=Y{$0li7t-`>+ z%pn1j)^NNl9yVpMk)_G6eNhC}q~oXxQ-!cJrrbQP;S47tPLhw7pxSuMMJXAU#?F%K zbn`7dadpks@tC5g4{%1MOwEL`%p)=OqV$cbOA`PEi!Uiz)bZL%-L(928vVyf2%B*O ztUvW-xKzGjjRw_FI7C=`kVZNg@zhK+W7;Bq?(;K;-pXk|=CO1P$3Xef162}9rbKOV zBX#f?>zateFUlhc5HK)seR;Al=M)kR=c zLVHYaiLCgCumHUBk%FFtbou9uS4!1XG;1wVL;#>8-*IYezi5Lxy(QwZ%sSf%vcH_@0{tn@Gfp4sV1)<17`NU@kQBz0ZW zI$M4vyH<;e>lz{phm}!I<~!}Dz}OJ&Q6cI_PdzE6c}yofto>!q<^q1&PoB|`_t1eV z`Xq@zd_~0PtzQ`VNZ3%QHlTuaz&T1T%Wds1!-~ChjVLjmjMX)QxfOaLHZM1I(ZQea zFX$>>mK+C+rM*>!c3H?PJx+Vwe({S=%8t0S4b;A&tAyVkM#p%xT-=!D7uyP#SAq-V z`*Xf{WSCBlrz`bwu*`L1mDSdDtfdxJE4nadJu8jTAv2iI%N^{8gprO-(5Y0HzC-b7 zz1?LQA218Qs$>O^MMgCd{Qk82r^tf({P2Vhh6LQ8nPDmIJeH<{*N>>#^8;4GNOI)! z?~IfA#$Lk>&RdL!ziH<1Gtybj4b~(nOK=%pcE0^0#@7+V=Q?t4OX28*x)!nK15|NY z#562RmWb2q$dW7hnR=>QR35%zRvJSV=ZUNn5ZRGvC;}AkqRZ^+iz5w=;tUz8Cyo8r zs~%eyTxbl7>L(h1^q1JfxJuk5!Rl>>h=5F<85=GFWo7fUBz0+^90F={NCxe)^rz^i z+eGS`HOZn(S=+s5CRFW(#4mAlDme;ODM+Cy1x~2~A}m@@HH(c}xFR(2nttRW^+ek^ zge#n$$X*<@wV#?km=efQn$I3tQzAzM;K3}TL`UtrS6Qh?CPT6@V!umXcIUDKcT$bE zG;``<0iL0^W3;Q>b+1|x)_Lq)TN68KVQJFeTq?6!<{8b6#qc~^@y1C@WVN~_Wk2A* z^~YqKp58L`M8$0(_@kXLiJHf2?T+T{B}d`@tkx0kNY^jLwXj5~`RYRBh3Dslx=kxU zPNJw2qPrYQ8Vu(_OrR8j@ORs_eljuvo2rL**8>MGA}ZPt>u7kNkhF-Ihi15AZYoB)pviYZ z%nRCR|16k~T@K29qTiC@jD4`J1bzi{4Ta-3?Gtq|{81x6qu)Ut%?rIk%;ca!hy$`a z70B+xX*!RgqM^_Uo!v8>;jLMOzRSW4c`kdwyFJs}AFoP99hA(peKj$3c2;<^B{_Mb zX(NG`C;c$+ML5vMnQQ}{71nKl9k*FUI!s&6*k6dEdY=_#h(6_GEK@Um*Sd3af)e?F zvO*V@R<}1@M;Fr&BT85w8k-#RWekIsL0a=h*Ov+XCCL#ZVXMf%m>tEwt7-QJIaCL# zj_ZjDaIY1JWqIR4Hi` zcXQrh$vXL?ByX@Zqm&arT)~ASlf|lmw?BP`ofVvWIohl$9P{4jNC0i^o~ZylS2J3+ zMkJljYe^+}!^1@)u&bI`s(Wc|z9-I}k;Z-}dZOhgC2NR*I1QDteqe$b3^fyj>f5I3 z=u3R+Iv+%MpZdrB2@VoS`FU9T#ogjZ{utBqwjFQ(ZzieL;d0e(;bOkn3|p-HbomK2 zDo;`({G&Ow%gyKOL%hAFJv>rJm{@?t7FNFQ76@hW(L&E4Mp7}D?4+9z*r1gxei|&ABt55R%BUax;kjDM|vqsx~^XNqxp9L2mv|GS<4E zbAr(P;~6tf6N+kFZ5=BTo7~l$Oqe&hgVb!$ce}XTBk8!?Q!Dj-4fghqdg%@0H~DzM zlDpra%oeu*bb2E3a^`C`iV#rElJrC0yk@At*>Wt~5bN~p7ajL!oOVYP!o!`y-$KC- zxr$#Uj-QUI0XZd+v0BPIcehci&xLMu4W3_){dOpcnzuag6!v%<)?=dW1RD5Rg9*f@ z0(L!UA5p~?FVVhcl(*M6n#s)CRg%rmHc)$ZHEZ)JpIMWD(A}T;yY`K5wMHTG0dd3F z>WW_+*AkHdFH3PNRo|6?j{TxClfUNUb_tmqT{cWDFHaQL1qIg~IGr?EF^HI(newZy ztT~W(2Z(*+>*7}2((r@k2jb9YN6KiqH}aQX4}X0=>6Glgn->Z{{!1gH@%6juygR!1 z@=m*g%ar7imof6#W#w{5@=dsYr2aW`xgi-TA&h=C1<#S8!DT_v4%AuUZeZSsf_f!L zV!O~OEC`EuaYPjd#q&wm#`9jkCH5}LJrNoTz0 z)wyr{xw^a4flZml)56I@V8`%`&FAVt5{T}siWs-@f<^1G6ME1I*1%k%k zpymOmFh3wK_S0aX=?ZFsrpP>F+}PNVCTQ;a_-nr8qs`o=HH((s$UxkP%EI}Y+3pv| z0KoaIvIfNEoWi|#x?ytO64NuX2>$tO)}0orp^hM_eE&8-kLYTl!Mj>zibBo6p>)=D zg%Af23v8OXQL@h1pB4a4$k-7Y^j9T(22P%B8QYn^NDXvc((HosBVO_P0J?)wVe_&p(5?naa* z%&B-dCCEnkl-RMemsiAuS?+h)-H+t1HhuJ-tCy;1YpU(Wnw)(W&8uB!$M<*9X`w7G zB2{DrCr)cZTHpDD2m{?MkwYH6+BHC)3Wgiv+VDU+XuH(?w|u#H$nh4W!nC57wEn4Y z(JO$c;!wO}(jHNCcC$TskzXky^i}SGhmE_j`oju+O+f2Cor+>RB zq=~QQCnXnlt*d*Q_@o&wR9aAk{+ha39ilDycfu(-M%yfx-xp{UB-b?dXDbmPR*kY7 zPb(8C>d!|`(VsFq_(3c!S)r(R#KKcoUwh@5px#}vj7&w(^&BbA75;Pl1nnN+)`i(Y zo72}?<@E42NpjB`bH8Y@N!qhQ-_3I)VSJy~-P6ONnX2BLf<3J~Of7&X%L_O`YmZd1;Vosn7i^H9ZBL ztrl%g1o3?Q^Ia;O4@&cGbs_koLP+sljik45AgSz+k7U0uuj6$&w*U9W63fZC$SC6< zwk2`t%$&#NlH)C>ih^q`OrginL&?J%&6cf{DA7eGsbw|2+XGp+da2!`=*^AR zlqL0l-NIx0QY5Rw^?N~0EObv;sF=W#!ml<)%n@JH?MPIS2XKULmY7)Mifde*j%TqQA0^V+YUN z_F=UG+edBg)6`PJvv~^wgA9RcX{5f~=O8vD_gA@U=a&5|_HCQdPUP}xY2zj43b~@B z9sgE#&;8hY29os_|8<#pkl4+LP)YA*$cTq+75%{LuI#(2IXL(F&@Oe|ZgK|$?Z(M~ zziu==bucZ=gl>)!ylj9-sitA-=|dvGccvE;wX9vU!D>sY5*N*@tu?I zf*DFqq&R0_5x8=!SR;3#04k9S3yrXgB|<~sW=$8toD;Z`GXV@g#nrpZ+4}^5I0A#2 zWILEzHCBSP4lNye+P9i_*Q)Esnp4+}&h=xDm(sKPrqPn*7fxw~q}It|=*<~vA=mj9 zj?E%Hrhk4eQ`kb zWLbVsC)pb_6~Ljb-s!6y%Mcm`6N%!<)zgCetw(}x!jBKZ>d9NL#x)n7GHy>$IaZe0 z7EXtmUT^g%O789SR!;;pSUNFFB_4kg+Yxt=9UmXW(T@^dVg17a-zM^$+4 z3w_?ok6Li=kIg!y)Q*-B9WLB|XSp9~$?ct9Trh2HE=JO1NfoIJspL)`#E7yE+5QK_ zcTus+NU)c|jW2idR^Qca!&lV}`>M_cwW_hQ+!LqLt--dZV=Qp>!aJ{S@AF=-Z^iAP zb|_n4T^Ppt32NDTOIF9365JQ{UxjtpjOFqot?-oB=o_5PQvn**!kbR{e3=LPJ?;Hj zbr)LHy5Y>qvqPFO)2lhM21m=TuBgfCZ6SJ|(eW&BVmzyrlVw=X1>*rP?ygg|*SNZ) zk=8xw*`|~Sb$zm4E!A;1g58Z;fxq1XeuN1wlBW|NtF<4k z#@Jh@M@J?D8pwXD4^zW*q8P>47vc^YV0t5?8LI6{50N5rHR3)N-rj=wiIO`gz-s(e z0&;`Kit~(3dNe#6WcT94G8_x(MpZC(4+$E8vne|HD7nAkB(5t5%SEh{t?N@5Y<1!E z!tnr54Y@#Smw_ZK6}fX=@{@NsTzHh^Y14JwAy(tm$+d>;tW`*L001BWNkl8jmWx21c$Y5K^%u6lLVRy=AV_YlE4+?}3!Fgh}Vnaw_^W1iE3S8c4%4i~Er zV{&V?%H0{5{d7r(h)*;Dwj{=9naS7kIcQr-H zy(p6p>QgP6tE;S{Gj)GW<;mzs5Mfj3li%(t25R=8KAMMJxp5bY+@RMSAl-C!3$4i0 zxP>&(AdVU*8@6x34cVxRP7tNGMMwJFmY(6JdK`RjAyCxEA9bj>n^oAn2ByL`tXK)= z{8N7BKVDf*K<$>~f0V&IssuhULLUN$5-uD9;X)q=Qcs znN_mhf+Ta6&8CO*sAh^G7p=lg$HUeJbq!gU(L;?Dgu-qvAZX6|z+_!@$I_J&(I;)Zn8w9Ore{jKG~XP!@);5VAGkvEkw*lB22McsKpMO7ebI}i_yT5=&Epu zgE_=R`sU?&7sfq+(ah$~E zR06qskw9ac;4?W9sc=3l4M@96sFj%GU;z)5_+f1u0-66f;4rYq;Yb3M)WU$+UDDbl zD=>nHeF*CgK*-ESL$ciwl1@-!LJHlPA#Y!xN`^L3telnw0Yk08sel5TGA-VbxOIx} zkwPpmGRd&Jtyz^yPDEr>R;gts`3h)eZYYYvc@Qa5#*yG|EZv!!QtT{{50KMaPr6T- ztLtHQ_jUW5?=2Agn(Pr7KDoxE+7iJ^Qnl3(at=J|5b4@M${Pu}q)89v37X>V#EuDj z%_M6|;{wqPIlW}ahEm$}K8Yz&6a<_0xB*CO*Nrt+SQ;slJwUvG6s}^fcm-QbmFm0Q z+?fDZg>h9F%-LgYvk==8;M>nix499Jqff>>V5?l#Cjv>v?TJy!rX}(QHqj!I_83Rj zw*s7XBs3G-6;|NM7IK)aw~*^9dBZf6`{aDu9Hd=*#yLFn-OX>wgRR=a=1cHUR*&xC z{NTKkWg@psLUvFPSpahNHNfD9)^BZWG7ilTs!GGE*^w5%-wmpEn?Z+xQm?M0ryLqB z1~8NCZG#^388@CxKe?Hqnj20hgKuXRnVEz*kJk;o6;n$yjYCmli>SxzyFRp)1w7Re zo$X4%qD=&{^-gNLG<|nw)0msOboHz0a2i zQhU~Td}MvcW0tq}0yuI<-PDD`!m%PSqkXqK>tJ6dc`!$&ab+;B+E`H`1tIYyEtx)K zRO9v{N$uhh3khxG4c6X4>HgVdQm=Nhi)?l9WM(yzyV`rQZfCnn3eN7)D&FeT$R)M7 zIyF1J^&xixKWE@afz5riug%(U^-i{{1R1xmUpG}`<*gh|SF(@qaM&ma zeI;}IGgk+aWoaU>1-w2XY{E~FXnmb8~(i1-q>gQ zY}$i2hM0a^&=4<wEMYTSKpM~zfy--0*;YOPTs!|kqb)BfvikZ}C&uqE3p$&E zz7?SpyJRvH=@!jZ`&*y9vwN!>Bn_;^6;^#>toRk49`aR97L%2S%CXsGF95D78=EXu zug5%pHWGPMgSGt{Gl*IcE>hBtuTC}d#ZFr%e%#{a$x=*2@2*Z(Dyvly~kT=kq)l`j?m&a-<}AE1CdTY!46(u6s$z4$pV(+=AWR5D}D6hWQN*8}eXff9dgW)CMzO z=psC4M*>y-*?OQdm;sU_fy$|t*4mF&JDd9z^_~E$#BAy~6j0lD;Er&%BWbKGJ5r>% zdRMEidm1*7&3>eNfn-OIr+tl55S|Za?A%hI?|yK_$xe;2O30*;CtE0`HK_*{rRf9P zdq%ZFV=n-Xypjft-m(-UNp&6^-@AS9gBhA@L7X`{^t@i3aq6ecLp;tK_N!cSas+*yh1B$*vMu z*za7KSJjt&1PipcJ~a}k?$3^_t_o(5Cx}!X-?x2lYY8L`(%~@YnJ9HwccyFOk)W{~ zCvDtEREJxUBl*d_2kJ3=okpO7&t4xy1~xFv3Qi8}+qXS{$nIn&3E74Q$kQge1GUFA zb=|4-f^dm;VQn7OJ?w48~>O0teyZ0VSZq+^-^J5m?fX+i|Zomi~lJf5Ac+iJ&KRPu}{ zELht30s{`1P|{Q&+1ORG8g}d==WzN>roYL>bz{{Pv|_hRHV(V=t>n25=6Vn_*+pIl4XLC*Gp){Whhvnof6 zTy1BHvm=Yuy3Ybwan^h_@kt1zMS8yn%pJ^=vywyK#N@Elo+no_#{{Z=wT2|7gjVP1 z1KlITO5yk|xa7h~Y!yec9_bDT)Y9&O&;Z$j&>S7u!$K~3G*Zwr5DJ$e zhuR$5L1K*1>CZ@!>==qGCb4^~of^=CUv;Rs?}Nq;l92(jr|HneZ(%J&ZZRxg z8y(R5ylTgpvdRlv6jLr>?J6mabVnjBTDG~X1Qdh@2Et{aGIZiI9HSMqAGt8l0)Z)) zXOljl?@lLAr5Q2v{0d81&_nWo>^A-E#BMLyxDX=GicCG(uR)=?NJxq6^mxOx;t;a? zmh1%>))eI?9Q8ya-6KO<^595!57~WdgsV6fb2zHTGP1E1!wZrk-!OKSR348EjQchC zus$$A{HOU08AtNlXV?R*(jqkqZWB+t+M)y9XNqSuMI&uzRy*hlAtr2$Fxt;#;7I4l zcxZenQY-X4E~mtmoJ^Ik}GUTCzrWwsWCf|+I&fuo$S6niv;hU5|bayO7gO$ejjid?hdG)Wy|I|0Okg>g~=^kwv_avnfaPw zfvobCJ~D6M$8%dNF^PTOt?q8}oiC%ZPX?yw0uRdV!k140EeyVF^~| z0nf6fSZE^G@(jWlrh^FY`8W@*37;&()Qmh>P322TrI>51LmYW;<}yk#Arj>kyFLKL zTbq`WT_u@5Y+g^98ym{+!OF~9=D)g(w!F+dvS}WV&9hc6Tbh9f`yQV+|ErkEWo5(` zSU~}j2^xL9tAlj^W|-tLqM@u3A|KI_vwWpDGtVSSGUOY-arcI^m4;eOJ(rg+Berlg zpPB_N&x(aBUqgYHxz>p(!51QNR>a~lUF&qQzo zU_FG1bkOEWBf`=&^ZGZ9Uy8>j-DN$~`UoM_7%^%pzwMH_!-6D|wP=S~wR!y!q&E?A z7_$(Ta_Ht0plSvumQax19ZG}9x|@_m&y+wV2MW6)$^10uD;!iWMye45kaaf=TDwo6 z=iwlKepmt=vADp3h0Qe^jw9fv6__kLj5^ug0&C`xa_7(-nq@I^NFRi2>Kdl$;llW!(7T0shZ}*ncTT#10le1l46XsOg*RS;WDcLO79^($c$H3v}Y3yeon2?XMG$+ah+1tP30k?9hx&{BnkOQtIbtfeNh24JST872(XxG9t=DTP~; zl7sxZbrB^<(mCtY5j%$jh7uH{g=8oKwy%pfNTy`F#;sH~&nHX}Gt8R{=sb~InoZ$Q z(jtG1dHG@&V5|pNO^OqcMYUG@DNmw38j(Oa=qV9ticlww{1j0C|DiJZ%X?IA#7G7c$xZQQsVOgL+G(R9~@ z)mJmT(0bXn0TE&bL5Fe8F{N(iM=5?c&ChLstXt?1n{8_SquPi&D8Fl$lJ9_ z|2*ITG{CCZ-Wu9X;SXGmN61u$+~x#42yu;dqVS_|1G#Ds0r4gh)k6r;8^4P8v?1rx zP7Z^#w~wXMremF>&lW^{{0W)MMB>eSK}u+i;*i^})nNHbtK?@W%ZPtp>TNq~JC95( za^)Hs90lRoiUZc2*|?oFQgHoJgy^`8{74FySQR^87;9~xTFq}gWUQa1MQZ4wDV9~z zywd~}_u#p9P7);HaJt-j9<6mRf5(-hv^}Q{jy4<|FA+9Dl1zn|3B`OuysIe`S?h4E zT-X%C4WKfz#|NPE_6<#Xi#w(LL^Lw67O*vX>XPDp6sYK0F|}BuZ5m?OD5CN{-p%O0pvD-K}4v@T-kurAWwv&Zcy?HO3F z$uI{l<2m2}mUefMtsoT-Hiq_K>*aJubYm8j{AKstp}6#Zjp%T_hJkz_6b?8rl2m04 z2|8TOV@sF%K*|eex2>3{fmy4fYsviZXS-METVQ#|=rVjVQJ*d+K#=K9nph3!R3n*m zG47sX0xw_7{iIkZDHOMyv3N{ckGUIUGrYZ}eAC2Yn5K6wEzeM^gPyjrxhSP|<+6i8 zEjhI3u0y9vU{jZW(`ZIgq+#2_z58aT?OA${-l^PlHn^<2AEY#_FK-*2?Q9F*+Hs}^ z)Q0`5CYB@}89g*U5LuKKd2m@zpHgsoY-!W5J9E{@o?Dl)8;lDZr#Qocdt&)y*YbOz z3B;AL6e(WY49q)BkmWyPGgkS*V;E33og7-$*6;B2c9qwTS=|S8c03K#y5aQPZA5mB z*mR{&OB<*uoZ67#v~*ZIR{rp>c4-v@EAI)BWfL)Yb~YL}O~QehP8Qsnf7MqJ+Um%O zY$$((_$0$ZsR!;?oE?3rben&bzQvK$+h1OuhYjVcRz8ciAV==_e9~DEu+8Y*q5;=H zy@omK)6`ADbn9*nDDLiW;*k~9JCddX7Hg!ZXg)F)(4e)Q4Zy;wVol(j>zjdxs?sD^ zIIzT9Jz0W>!5T&=To*JZP^$+*Lr6o=hsYK2n02M_7|7A@*OK)|v%_~qHmnF2K`(;q zhLoGaMQZLS*{G%EP8Fwy?pM;r^PDg2(40H_l8tLs@yBq6S~xW;H*$xPG+C^;de&H1 zZVBBC5|9oOH7EfF3ENrXH|ociY+B1LRQ*xRGl~k@^`O&nm7+K*gs0f4lp(*s6|n z%~fktd$VfWv1RSponRY0mO|PFdV`vb86%?533Q@3gL9C<4<`Y1l1{i-5D80j!T<(K zGZP*R;@DOm9Bj+v^uq|LHP*I;j`r5-2e6WP@I{d<_Jb3l>6UV&Cat8Uqdq#Csj5|% z|F2q`oHH8D&208%t*XEN%U6H>by-#PgOz3#-KpA;9sYhPzL#eKy*Rx@}SY+<0){VT&+H_rml_Q0V&Ro_t3-8XXXiB@<3$V*B5k+@pd(OcP-WR^?B)^{eJ*i>|@KnAN~QbgGP z`|8qiM?`x!#PjN#Zhj(}c=?Cw4I+GTb!lT+JgxlPa7pawAa?d@=l<%%p7QpbSUEZ$ z9eB_}w?1yB$2oy-cV_S2d+zv3OXHV3={NIo&b%>x`!rWyb#13uH6eFmSU73XV!4DK z8Tb<40XZN;)kdc@=rqcMl@!8^G|ZKEim!tYJD%GnzHsN1SY_+-bHd1*R}O|^mEReX zy;ZHQ^A>0GY?X@_2%GXCruF{!4}KyZ=--IrC;fEz!In2FM>c(4t;QR?!kNCRwARIv zoGi&?N9Ba)J+Z??D4y9Ci`M$MmR=?G_cyAmukm<^EBL!B|1V46{_>mpY6(R1CbQUC(AkCpVL?Fl@Vg9AJ+$`fHwHKRMcMu-na&>!;hOoQ3w^&h{7btz7AKptgFD8L?&#{fEw^`j->CkzxK(hPM`$s#hYMmZz(i|l^Y3LdJezM5& z;pu<65s_@q;lramL=M}2;1L^X?HT^ZD?f8B;k6RrXZMPD_#kYIC;npe`;(-1?aD6? z<;mc~!v2jbg}&7@d%k!a?Y{H&(W84w-DtVz(4qXxUx{Vgt3MlDK6HGe6o}_g4?J$^ zUb?bx_Q}rrnNz@v zUUwWW9z0FWqy}bT^@JqDt|_r*a_}qJ)oLBM^(~KC2UoU}?#EHv(&QWWpX^oLsO;TO z#N64Y(^7Wc_)Pr;w`tqbTbu8f_SVOffAQg;Pi(sW{-MJ~uG!V2JoXiPH2k?=RU1a? z#*&58oo~d;hYI2Fyg*Xaz4m^e*v%p@k=M3(QcPLa-zvTK;qS&dI42Js?%;;n))Y*O z5Io9_E-di=&ybvztGl>xXS&p~=~i{REEbZ|;|s~kH>fY{q| zFMjs^*{JRA>h$93OF`X7i;JZ~+ZEnOH=NtX<(Yc_P}FsX(YCWuxWBUS{<)U=TRiEL zw^;SJu~B$zak58^>Jd`U$%)U# z>B`8N*GQ&~tFm7xFOq#rs;6@Gv%PXsJICWBIa{1DV+Y2@sCBa7Qgo=85KqQ4lJd>) zO;Dps+u&2(mzC5^E+wNEnM^=3YA!rdV=B4fucBbneX-y;&<74N5@n6u$iJ z3qd$6qJ|)mP_Py`QSqH_h&a=34)hbcB<8Ew0Ex5kB*m&!$Vev=WUdfD!$@X^|%_zlx?c8Aw9S8^H_8fvCiblBoR; zl!N30ZpUlh5Un(T=El~~=>6mvvGZWaWIz%toU1SX>KtADYN*w*V&c#pfa|B~q&pBbV5eoMm@g)<>8#;#u-fsyF zG%QG5E%MNP;8*85d^I^bVU~jw%i<-T(Dk6rApjBLB*(HctB}+epMW%c3FKZ#nh)kUde`)ffUb#FA6iHO zdD2xgRkzlHm|v#n}BOlc)GVD;G+t4^dv*^rm zJ>Zuvf+EGZty?;jsQxc4K|G~l{U^*Y^~}B!5LZTR483GeNsqy&7zFi0kKb4 zG!2otvy)iM(AGl1)ilGxyP>>6mo@Q8 z#EBjFMVc`_3n|>u3$ChO#Q-h@0yQ0Ol3rhYPnc65s6zY1I(!!w6(R+*}6?n3emdORz1vPwJkU6SbK@k(~owEuFW^!b~xS~ z*r2W>Sc+HsEpXLG+9blFHWiKz3Z8HD?4g{OzNqjS2Cn0)a~=xUR+G zuBOlBCX_-yqQ58gle6XUq}<-D}Rpm-DQU3HO(`^K1F7t3?S1 zVl8SqU%9zI25L2K&%og#$#xcY^AGU=gFta>$3Ahf=kChD;ZE36)YQVWv)7;W8$&k4 z6G6K~mR#9#dab2yOze&T>$_(QYceVhjqg1y^tF57^@13Xlx_j z*~@u;EgzAFf%~PyM+?Rxm_LXQBnb171LH!B18r|`kvX|tWP*AEhM7DKDrX3or!4Hc zvz^;0`$75oD`G0MXF%wX3w_b-Fws~!N!q`>5rteo9b8Qf0|Uiv;ek@I=TM$B#q$x{ zC-hTn5v%6zmk%8k%QJ@Og`FDq9qoxoclj5jd*dD6X0#m@3+DtKMlzerJEDLWbyPma zMVeM#3OQ5!X5K~wiTXH&v7jXqfztk1j$(~f<`$Q?(Kqk^SB57@cZvh(*5_JoC?X->93zmm-kwNfS&d})Hnrm2h^~1A>mh8 z9~pq8X@665m^WtPF~26-j8uD3vS&)1Hqlr)bm1}w(%8acbv~-QxVZ3z-eH0?&b~`> zqw~?8_)c8jMH*&j7s|VW18WP5@r~^8!$=Go()~-{ai6_)dZW51^piaEUq4z|T)PyB z-QRQZ4LZCwyU1()o_HoM@2ng6Xk+SEhoXk-U&wQ$NYjGY7pFHC&kQ;)HG6S~#N*Lsu~*J3ViR~e_?3Jv_VoG@@%*tGciX!DN^syI z%S1W3hKhS{(U&uo-v@v#y4G+Y^LTQG^DSXDHpT3JLlYuQ=d)14M7>h%ad4zd&bxIl zi=8Ft@B<=Fn>g^eC1{c>J%kRDHACa|b03T2D53-3HU~i_?5lp9>Hezj=Dl#=^>ZT7 znY|?1pWz$H5Te|N!BG z$v3UOL^BQXTVgSRW4T=A?OgDy=_ma}E)JlibM}((D;aURL&Sa3f69ahxEzD?UiH>~ z8dKz7o7AcjarwZ;!qmS#KChzcrg&-L%s;;ERaHJ(%BtHqyjLgq&b zTD7?Dw727YTu5vGl)E5Kn;^N1w}ZCID><=mf8T>ptojoB0`%UwGqso0-(UG`X|knh zeJ2qyO>S&;iia34i}MH`K7VUI*!|HrH{|+`jMfiHp83y-y%p-`-f52)K3h5)XnkvbVn#~r*hkY^zg!k65_NxnI}r1L$pc@T?>}x1x>t9hXPa$+ z;kg1T)=d7KWaECWGZLP@$D+DlPOt6_1HlfmpQ#zCsPeD^`S+k`AC{;=)GQWoE0ZBUaQ^I12x+|kWP0(xUCPeA8_?6G zO=6|Tf#sI4b!gyd2WgC_22QcCX)Qqj$^P>Eqy9*(Jh@nE4mRDqks%G!0!dsy$w~)> zq$oks$NSnr@yN#1Q~Je zT6^_UB-b#jRVAA%?{S|rc9}DICKAU@ICaI=Nn;WMk#?l%Phueu8f{M&+t^AxTjEQ}Z+GFk|SPh}KO^`Gmc9-acGp zA@{qpqQ5DY!%@SO9$q#pH_~k7*j|TF9=x;z@yK{Cs3z{T+CbUfa}^57I(5(`PMdi4 z(W#!lxLYa=&(p0xl!CtU_RZfUr%gn%b&G;z8-;ov4-k3QOz`qUak53!_T{)(y_m`H z21o38F(MW_9V&cyr-{dr{r72T>v7xmnaYyR@(*RwGrv+gRQe zu{K_2zb->ErN{w3HPiV#QC}1jh=sgGp#`Mlc93s^kDe)IAxsjgHkyK?dI(C!$BQ0f zay^v$0`&1vHRxX1*%()6KAn$pv(?H+GU68h>SzB_H0WVlyi}cx!sGH-kZ`|j-CCkO zUsU5K2kS<^*r+aVExUDLuV0SO8n1^IBUI9o=Zc|@uB@mzsrZ`~_& zFxgf-U&x#KB9u}1`}Ds*C4cgZ{+)cnU;q5SKOs7b_TT?W69i@IkAGr(3pB9$mT`V8iOA%t5?+htkZy7gk$BXfKEKWIAZi1Z14(s- zj(kK5+@yIDi3P|qTOBv29Ik#|j#AStauZrPM4q8r3Sujef^vsyrkK+yhBKk5Q{e|GgmtDW_npKc`@ggh-B(85oZyInHiC%A>}j4 zHXk(EO$_FsdNGli%LYp+n3#YikQ@;OHpZpqP~k6uvsw#aD~Gt1T%hNVB*e^`23_Y! zp6mIyzy0-ZfBPH!CSSk)E&k2F{>Dw~U8r^6A)-^@LiNAjfO3C??vLL8tw0j?B4{2~ zyPUMOTDZwWxN$t1^MYShk&O0=r>=OgPQs~6oKd~* z&mfvw_agt9GXk)13hIa$fExSLpME1&k%=8v_*z;Qx+1<8b6PtK z9tVO61)^F82Cc7`h2Tj^qE+B^@KB66coGE%(-raf2(CF{*AL?vTS)I&Gt{Rja3uYf6MROJeJ1%YUO~^~S{uQaa{+3B5A#`0VV8|CQJdg-`ou`SCoBZwdU(}-aj3FU?5-_mmTPU)E^-2&k z3QWw6svW2?3`BcVd^Ai?_2+5VTxGT_<~;uP56#LBNiwlbre?6IvY4zxHXf4cq;{<$ z(J&i)h<8#Ybbn>KGP#Xp8h-x(Jd)2}-H%&Ts;05UIeC-~>SnZ0PcH;LhkCY&OBN{N zd6gnKu7aL^m$>LDy=VV~AIB@4Joxi>OUhx9I>Xd?u{PewIaTlrk^ev)mj7;4-k&u|@ z^*MjBbhvo#=lWj$;^o@(RHA2IP;ru)cd@_$K_m89COE;trTzx}jcF?!~VBFq311fKbCy-!}CU%%8zb5y) zp`9HG1QjT<;uPovoZXKu^^C6V)s1JuFzI`8Zl8L}qG_%gU*?V4(9LQoPY2_bqFBW8 z>0DfDX`1``yLkO9XyS}d^8WG#MsMCWMm|>*6TtefkPqrAf2DuDDV`rKZ)-2_2y*3D zJ7-=AvKKCIy7{p)9vDsLwZb03q|(MsiH)IPxkR)3m#v%&#N8YbSHDPIoutV@J6 z%v_zRTy7!x!Akjzi0t1iNfKMd(GqW#e;$a=Y~965`3PyR#E&ZFm!1wL<&)INp&3Yn z%?|KARIhNQ1_92Ie|U(%^y-W;;6M_dmF$|@5sHb%AmTCY*2Q(P;H&r3v3TtW5vK@! z@rRu%Z|?JZ+?WNHy%=vyZO@&bji=@+#omR_r^YH`okzTJCdz#@B5W!)caD=yc{O-> zv01UhL_|3vSI_W5`ndVUMku}a<8L^U68!HeH%GZeaq4e!%+|B=jN}8$EkSUvBOj8@ zbMqaA0(YH%Jk=IoB8B!fIfMJ%$L;ausBX0Md;u;~jl51W%L;sKqYA%3@h=5l^d z)Q%)n_UO6HbB5)+-xnJf; z%H13%h0c7Go4FG8F6@e0r^m&RtHXRA38Ih$B3qyUuNh({Cbq7M*nq`G6cAp`n;G28T4?f5=RnB&7UD=yJpEgwv%8=y4Qb+69eD>B? z!_}$jGlP$>eSPol?Ye<})?4kTx1RKiLvH$3I<{PV5K*wem2e1_3Z2`yqiUVKCz_(~ zF11cikgiJq^ZS!^2V6WccM~38$@i_ah+~nO;>%(fv~Rt?K8UNOZJF+}j7A#f#)C~4 zPLfPcJXM#w^*1~d2k_uLv&#^Z`Xzl5QwtWE{wLbnVF6!~tZz(Co6tX4CU>`_rrpGe zTc?Vnj}ErY-7cR0-G9v9oG-rd&Aqx0OT~S$K$6VTRk_`IvD_h#D!4e&dgo^sF6}A3 zc(YV24lg&0x#IfkzaZHUs!xhh+w4igfmuH{Ufew=meU=7AfeK|%n@|+UifCb@ormu z!2O(=j5LV=kpCu-OU0tW1Z!cZ%R<8!+E*cGwV z@#XKhp~Maoed1~EzK1Q**5#;=D`xY`PFmN~(^Fv2t{)_F&h!Kcy2_nnH@eEt&0QUw zZ(MlobcxVnanIU`O}8!w+0pS$H?PQ9aNHTl4u2Of$+4^9WM2R#*Bx+eijyr`dwPm_ z+AWdvuw(z)iOwiP`bvxw3HN_p{W>7^UzQ@VQj=0SgDYq!v!QjPH!>Va&Gf^0Jh{$P z-z}NMHltSZ*Wjb%ShI|rITA=>Nl#U_!^;OVrZ3nVFAS~ijN0PL5U(V;*`<-`@hCgG z_SyAPbJDKUtzWJ!mgFfBEF7GFe&+4U`$JcsyH#CWtW3VJc}4F0O~i)LPj+sZlcz+~ ze_35zs9X{5`=La+KoaF#kWF)!y1rRmtW-`#S-D<-szOu{VZ(_87bfC{zK5Fb7;KhY z5TWJ@V8?48A+9w1jQdJn^VCLo_Uf_uw(`%0=jkBV+LQiGW1on}|Fd)Nh^+=9*e@45OiU#EBn^1+hfd9ki4cep6_0>4;(K|CZx zcfT$l(hkBm=L=#+zq{NLMnTY2?iasuGwR84Lc}Q%nTT|)@gVB%6?sZTIY#AgoSl@BB;JN3pbLJ_%CAnA0cDi-B(7Vzc4nNtc z_J_>=?Sm+yt#vnV1mW@W^JAB~mbcu!I{2R(S2>c};&+3l_=H&B!I6~XX*S0qx!kZ( zAzbV*ku(?=ZU>oA?=UeRyG`-jz$YrOXm z4*&NXJal_w^!MwNdpQ(-c>DsdRzEx*x^^bY%hM)E-LaADcXkr`#>nWMgAv^`a((7R zMA|M~o4KL`!LVDLmqSVJgSC;x@(a9;KX~9D-;3Iou8oYmN}f$liP(DW+Q{rgvp6d< z$F;S8X=LQ;Ub6ez{U=1Kv*W1s~6|nR*SbD)Zbhlnf_z{rn`SbvN!Jq-H$#U-QaOjIQ&n4 zt#=6|xv`}285pfrCptp0{)G4Mxb?5ckL7%gSiAYVscVb(3fycXqhh7+t@6moOX2Zv zw~=6IL>|I7z>$=pJsl!_;n>w*oxjTJ##V=}%2nrk&X4qGpkid}hMx10E1JXI14D9; z(Xe%h%a`pPIrpoPy(G*Iyv=d7Z)j*}L>!y4`y6k+IFhc4g_^zBu8KVi_6R;g(mphD zC^FEjJ1l3TqwFzGl!sPFqxy5(NVxm_$kk$$Q%6@^J3n$Z3hR2d$wMu|-jVZHJHp); zI3vYO>-ix;H=pH#pDjdO{_|JFqXoS@4XI&4wXS2kYTc-vbxic#xpdD3u*g{|kWZs`#ZASZTi9TIv9_nj9u?b%!Rc3sbl zt$XVZ6*{?>7#ex4XS-Mt%m0g$fsSr@jkiPH-~4sPu-I8lP7M-<+7<48iSc41x_jj8 zmP3&ewt)lXZIjFO-Dff z)ZEh?lXw%SW9m73V<;(8ModBm=FCQQTb{;|XkScU=&d-Y+KeKj)Fh6?$dK%@c)Zz2 z!!nT~6X-&CdnUKH&_I$mld~+qe3bN7`m_m)2opnZ(3Q`Ws-F zr2|AQJJ3nZS^!iLB(%iinsR2?oH1@1H}-#e>Cpd{zkd%JKt`F19uzO7HdO{k(5)E~ zc9O;T!juQ)xE+cez&d&~-K^$NP_k&S%Sx<&VBmli3qav*9K$2dVK(cqslkNdLHr9e zPd2aON$j%xI#EiR1xC7im>nb|HOF{_1UMujBww*;|Yn^!ucY=lhXfkLh zr$h7VC3`STe365a=6dp%m&c{#iSuIqC6SKVyDT}{H`$j?QWjIyUV0`bX-Hk?wxpE8 zwuA+i>}Zh;HKvqq?`2d5{Z9=}CT|q05w=0VyHGUFXut*Ptkyk)*&VIhz#J{n?CFpz zWr@adf&;@1)%eg4zZ2LhTQHL>w`xOAF*zE#HCc#>VIi$;pK?$5Bd`{MQpHXM4V}e~ zWY-WH96qe~kOa(i|1fTz0THL|;mIIop2he73O@xmS!eO5wUhn<6DRE0_#e+-{HX{T z#b=%rip63}TDpeG?PTAb(yQWooj9oSf7u^2x~czo9KfB*M>f`2QLap1G_dkx3x+O; z%|Soh7#E{)hYuezhgr$9TkPOOPtU+%@q~8kz`)@=ZIw^v>+Ht+F|v8)6xkDROo$dO z_xT_6BfJUxsi=&3l6$>iy|8TET6uq-_T(M5s2DVuAWe(kJXA~t(~DDbEs{D|fXI*B zP`^eue;20{!`M>*SI^FyS^DHl@uTt%J7?QFIa2z?|Ev)?!OoeN{Iz%v2j(WP(Kkfg3xL8ti`vs>q*oxKisJm-aVZ>Yhc zE7T0RnPjM*JowQ#wz^n3#dHhN{V>_~P^N77yY*>tD94_7X1cU19R7ZKaa}Gh$z&2& zBcQ{5n%EmVLr3Mdq@?$(EFd}0J@Nfb@w;?b>kd}JJ+N$&F z>*ZI7UT=~w?jUbYw&=x6=F{YP#xWnd#CdC-+z~X)yizywmK;8~a50B|W-b9Tn5_4v1GMc|`v z#>tqUww2R)j8}tR0AN?dw|k~`au;&*L32Qh5oy0Lb%^8!;_7GD&S;(*D{lq$U*4#X zKM^A!;)!p1w-k|v3)jv@gyoK1zbeKRd#{Z?>Q5d;qNMG@Rk1pytvGP~9M@Ow*tM%H zYMeRJEl#8)UDrp7ne0H3(6-l~<9G?{D@RC!phN0v+K=1QnBO z0Z8}y&Wu>k-BlU7zIKET+*(4^mH+@C07*naR9zQy5{ipPG3PioUw3O+ES?c(BjnL6u=kI@&A>rUR<&njEncVd|{3B|dJ~tz# z%X%wAGb_6`eLm0V#fNoc<3W_0`^(%hPN&@5_;*i6Mpw3pG#6qq&wE_>q=wn4q2N0) z?Z0*Hh^UqgcOOQZV!6Y_dt!%)`R4G0QnJH@-Lq6lU*m6cS^7a8Za2(b_JNc)!MM3V z+)MIr-^`9+PvsTXHo7d<)Qqj(DZkf3F5V{OSSiZ?lmy(#?=ElS_}b2kx|5VFw)7x_ zrIyUG{}Q}eih}lXYHan-`Gc{c@hPCO15uIFL=kGbDR4c2ZT~<9?5Gm$T0-HT$z~#s z)o2^5oGFMo$H9kD&|Quq)y5<~sWHA3wGMw*E=J+$jmqLgOL$x)TW+D9QLy>Z&bIh3 zgY4`H`JkU58l?U9n28@o77$WYCCb3G3Aq+dHXZ%FVE?-_IRzbTx1dVsnaXF=&jN~ z4(qV zdbG5-vAi?d|3FS-?T_PfKdHZ8U0OdIiLLZUADs$Mul#cHHrX`%U1ceLa*%tErTE*O z-C_YsCGknpnuEfZ^p#q|?&U(?#_HnY@BUr=-6ionwpdTG`1OP4?A(d2a&va9{C3Y9 zYn)D8;dJW74m*_-^_7DpIg{e}L$O^2ClCbT;K~axFU$2wVuuMic_J1CgmpK?4ilw_ zepn))hUr>^7KSCE6Mq-`Cy5%B7isEFFYnO()1(`ra+=+QYRfKpD4W>T zrEctYczpTin{M8Fv17|Na$vQ8%ivcb_fDkyTY)4ILW!+>Zj(%SdP1y-2u_#xJ}*{c z5yb-P=xZ4y=jgk_z8e$~c!hzV1}15XOlp1wi9lm#=k*e=_53m3F{MpwCrEIh^xW9J z7q@KTy{iMl(NbDhEOzqvX7Nh#MX`E^1eD17)J(_MWlZ^;fFxM7rggaM2O% z=&Bsqba$RKemNc;SlLqO$a7E?>*M99t8%IR{vUSI!oK)wN1hg1@0R#Yby7n6YQKD1 zovH;JrVt|n;4K-X(Mhx$(IB#{>-fhGVnauTU5ZZc4js5JzjahYS#r%}Na*mR{^y2E z%?DOq6i;lE_O(-6cnx9VIl!SX0pbIBH!yBc9)GTzt17o^0lxqfii|O^shJ?2P2TDE0Bd z?njbNt$IdvdaPTO7yh{Um$gvRHZ75`G}o4vVvtDnnfE;Tg;Au3149p0{jXA^#j=NF#4AemVHzQsej_`g@7Qf<^tOX$1 z50=DsAK_pu7FpBq_!rf2qGrV!uDvQIW^;2(@j6d(e1b*YH{<9=jpoV*R3z!|_g%l&o9UN~lFYt(`{`xDN z&Jw3n&&$g3&RgSRb?E%1@Xf^~!H*~_$V8b0{Aj{ixSH(PjmTW^`z@*_>8LXCB4+yD zWK?Mxb>_`YY(N339E}1hYNRz$U1IIzY9^x|k>^*%!Ug#dy!>fmc>BO8CP5>|y zBgURqU20HBpRYk>r-)IdNvao5=N3QKmUsUsprC%Joz4@ER5PXctGoL*dh30a1Rw_n zhsLXGNV+@p>m~v!AJlfEV&jkOL(0U?4!QrRR+RY#L`i1Asop4`VP62`0B*y6fo+Wo z7Y2alrLnm@xLMK=HOeKqDgjS!H_Vp%^Nvo9m>RB$wP{AzHJsk)L#Hv?LP@ZC>jviL z8BL)D(;*UvEMwvCt?K~%#L z{WEC|HRGKftvISv{~9h#wuEj?GCwtlZ06*oP7nZr`W9)m+Crcbq0lK+(*VWXa%!_@ zdS-PAgWCiGo=w0TF49mlAh++@lr@oJv8-u2ckSe_wV1QO7wtu!9<$%?lmfu{k(0+?y?RHXj< z*uq~O=%kFZD5&|9?@CXuQQ$X_lv?uw`+x)hDG+CnZQFZH$Ar1+s{$mzb;iUsqV`YYBp=Lp6njf@Z3Dp6udU(iu zSE^^UkWq=x5iC?mVg*kC3BqJIHx>qg1^h>#HpYj7d6mt?FNs!NrMQr`CUD__8qw78 zamxfAbO5Qa+-YF(tVJwXtr4(28KMQmazqPKd@eQvLWPT#wBZr#smwYnU@GFH2i=EW z4_U{E16`f+MXAp!S}=Qjs!#j&6tksj+DHRP5?fC#m>hK1@YtS=#56}Rz#u4c0cLag z^9`d#O1_kk{`j+17UYU~93Y@E4==U@ORbi*fL0@n!d5X!s@x+8lyPN3 zZIO{5U&24hl*cqlZtG^sRO-P1_o-_eXi1GW9FNL0Ipz;JX}u(A z)ejV^S!2PxT0ZC>kWPVsPMMDCJqO@pkN7}MKAalq)B%J_+%2{)fS^>i0d?XY*zlTs z9;0xS6h~<`I)WY$X$COuUt}}@<^%x4S=1MxW~Oz5Z~_7e9}S4Stw$-ya@A~gXe?v- zVw!bVVQJcsQUIB(AM{H$o|UC!(O%}lmF5>O#i<*sEsiw&FCix%Y@P#}64or7u* zgh!NJ%@9)sY+-uu+ce!6^BKoy#ITsNKGbJc5uv(zW1Aw^?3&90GvO>v7l0XutmC;- zSi@%b8mtrm)v$8P3sneLpFne3cGYL7q5L$(x=kdI1btzIIztgw^Pu^6`y0eMdrz6Q z`y3l!xurN5@tQJ@M9iWI0=<->xoEHI=25+wy=NdUjj_!E%Iq#)SgFjtxWi^-?C z9Zf(48hrvCprA}!&~GBFfJOzrmF-1Ol~xmJ4&Kq9YNgU(hRl(kM5jSz>*CXLIH&;) zmJd~2G&UM>VCGuEdIYR43ko+tHYto5t%%xV>4F@wQs$-Ia%%>k;Aw7$rZcjn+0Xi6he;<}l`PZ|L|Pv0l{r z8E|^Laj{N4vPn}JhF0_ARC8VF3XL)|`(gYm)`}}V;1u45G7z_tCe9h%B%nGPGpYvYHLP$zmq3ni?7(a@1}C?D8!^Xg zL7)%-ES$wk?ocv%4>XEXb(sbU$Vr;9t!R)Aa~vYh?xMp`GNdg&U>jfpCZr@w(Th4D zFB(eFX=5D%t3ZZfhuHy->lU4M-$w#~wN2=wNfSgIVPv3YjM#bun=>#L33zZDM{Eno zv3Mby1CXfJ&8aa@aVl1Rg4iK80kbr1rZk%1!&Yhg)1)w&LF>WN%F!XHx~OJQy=tJW zu2We?JaLiN1iG%#*8prPn_zjdEwr^jPER+MZ;_S&wp>jjq(Mv(8zJk&SRlVHdED3p z)Vr9>SAa2YSYuKsXkF+@Sick<_G+n&!Eoyfl!{yv(}pn#nB#b@<&6Qf*#IkAH?q_e z7Z24%aF;GcY>imvI44wlz!-r+hvR>2E=vaE%MQIU*#0<5!UhMZb3vq&>5_Fal*XpQ z0CrRcFZhFx%Co~UZly6q2ZkY#DWDLW9)3bGT)vDcY?sri4HhUUutrv-8c%qM6B<3K z87jb^5a+(Q>XUj@2yEvd=ozSRj@F6kqXB*SoLPLp;hO_OZcOgI>2~n&fL?vyc$FW3;uS21S zYlb8rGj{cD3!40Nl>-H(;=;ZXpP)TniV1v!fWnFAKOiD($Hagd7OdGP42~z6fzdQG zYb!wQrD_OWMAfBMTZ8b&pg#ODs;79&MCH0*L>(Ce>lXg3X-s~{Aovz)1em5%)43gD7CKu6HtJWgji0)_*~e+^ieH}lopW42@Daz;QBiwiV(iQqyB zsuYktoyG?INM^0E#H79qUQ1 zNx7F2+f#ak`<<7#>g^m*ovT6SvkwJv)VAw+P0#UE2`@H(gtdK8%@69kFR$Gb6OX9~jlp z4>@{I@y|%eS~fC#yQWPi=XG`r2x^z;Fh~6)uGQ0+HIADg#af-EDc6~qRg@Tkd_!2c zBP9+_ZPA8Ms&?T3h^=3Q>DCRaz%vURg%EG9T8%?=ig!aMq*j7ZjhkKA9z6Z!{V-^; z0&DAdm_ZeTKny#hskKVfdeI7n_0bHdrO4<>;egNaSZP)TKFVs#oM|Vhel-iY&fmAq~ z!;=>pQlF-7Z&Rd1k{~jAw8AktbnFg}fWyUgTEW+=1jG-3VG~FR^fol5aneOWe-99= z$GFo<#YB(<*7u`QkVq!Wk1Jn`1>Bk=h=-fBVLgCn`EGFF5U|zOSQ!7d*_=X{t6uHA zT#ThF&y^R}X}2SnGByCXH!{1ifDZs@IhP)U0*sRHcVfx1d}aYU%Kep)i(w2r7CSKCZ;>!xwMgo2U-msBOO z8rKOV>LyG5jg4S53oY(wGKG>A+O{zI4LUE!p#TyL%5OnsG$5`9Vk1a>w`rzdo3w#{ zb?vMR_ZSrft#{IBHA5-TG>)nqg)6?&tl=sxvA%7Po@PxK%TA%@Kjcr9VT_To2BiM;hf$t(7RB)@TgxxWZ0$#nt@RVqcJ%1B4DIY-w62)X-JFOZ z&z2>iK;jOCrfbJmI%`y87t@*$SUuA4rwO^vL>td&!qiAc5b6vbuuzV^h_1V+9M3ls zU5`++qwfOwV16S4vQnZ2&75D6lrLpo@5`kNEd-TM5FRlfAlihw_DpKfmR#p?Quq21 z65jf=IIto+HZD#N?Tr^^pZwcQ*W8`B+>-r#p3uR^+ezE~2Q79fD(vq-b$UDl{dpjB zS_Vfb7Y8ZT%x2fQz;|t1&^1WwexZ^*+F(GF`0S&2%dV<%#{WE#vG^9Vhygng3UesJ zN;C(vt}>PO8O-@qiQOwUCBPJc!#74jK_+O6PZHX7mbY;v++S{?q$xfbWar-9bn}xS zoV^nDE&n8U^EM%w+*o;+BCGMC`$aB74Qf@(;6(i%Xgr~qZcs#0btT;}Shc>_1TM=M zEfqwJq;!}-85s3x%-BrnNzK4jnmsL|uy6#S6Nq5&V_&d^He7?K4zugx9heMq=zCvA zQ~I?5Z^Pn~q25APghyf5$_{a&K;svypG|-Lu(`2vu&uH~Yyg`3;j1VQIMflh43T57OsxlFS?j`l96^bZR#Q}LC3azm z`SNQ!G_<-B(6;zqMCo98yUenAy=`WXUpke*pdOlZhVAwPju+%~*ys4Lj zP*N-Ab5xzmE^OW4l#l%Z&8n?Q9F##YkYH))vgqBPezI3wB-vq(tNk16A1(A}>hH!? zaq2+!R=Jtb+{~3I)TBGUP5$yk4@e+hbs0}H1+#kAzQ%ThRSK+YW1Iv^u9ZNuqe&TF zu#dM2O5@K0q86GEV2l}vqg{Y4XjPxA9c6&5`K1~qFxBK>CQLer6NeEjzl$ub5=R#) z21nlE+8c{ZEu~{k&llp4Fjloz4=$jLJ*eRa_)61*#TD8BE5%ACmt(~ASf8LMoRS}bl={V>3-+8EG0i9n zke#Y*2RWg*IF&b6Lab}B&eZha7^*v#6A$MU-GU=kH5MvhY`Ln1P*vxa*zQDfCV@Fg zo*G#I7lhP3O#TXBhgMg1GlptZl@2AZ>R==515-fVAZQ%cQ9kHoIQ0jyXUf6h0$`Qc z+JKOYDsY-0xWKf&Hi&S*P^RZ`f!Yj$fTR|=Xrc$A$tV*+79bi_AEzBj7&A#d+FJd( zb_KR7pdw(rj$TAXA@+o$)GDkcXHZosc7+!hY?d7(8xN(-U<=jeaFLP*RUoF@(}GTh zfR>2B&axZ1!`g*wLn_4Z1(V*_3w7u@3k%R44JZ0VIwPk0ZAVa>AlGG7l2fHCS)9d zEM#;T6=B-M538Jz+J-d7Zm3S`Otw)&J_D0RB4`$M^l3(05D<`Qo!G()0F~PTv_V=W zQ1ZN+7t~pEx*?go>wwD_71t{4dU2!f1--bEV}A(+W+uDGdn$GutvdsN038@94jJr` zfamr~OuK-w00;iHM8*dZU1_QPp;M<(N2GyjYSk`{U#HQ7aVs$mqbd|dYVIpYy{;!> ztuB%IT*jfKz&OzGx_m7m&W@}Hz~e$(N(2p+V#m}q7Fe&$)+EauL>$0M8a^E2DMm`U zYCGA~%p@D92Ggl`ZwSPCgLFd>TwR>%>!}I8F_@NUH-tb(p(oUDkV||Nod5 zbV{|_Y)(DO1Y0(JLz6|k!bS?B!bpu7_EZEJH)7+GZ8DtSu|IKP2Awa`3CPPlt)`Gg zZ-8aoQSzm7XkiR^y#y>OR*%W&$q#Yt4Y?@dIFJZ{=OB83{M z)plAzjUzx@;BvLNCLiDwcQia*qH;hYcy0+O2UQfNd)iR{Zb?c|-6?Vuq=3o{qO26I z_C56_O0{MsI#$5fQnbrV;kpwllRDiKw|r=4BO|mrveUn)8fMQ-~1kc`1AHv|qYE_SeFsoso@2Bt& z^=4`ZFcWh`aVi92&uSCE%ky*2fFe?aJ>?HbYoF#$G;TCN5GL)XQH=&Q>S6%gYF)V6 zFyg6S)S4Kf2dUUlMakTj$1x0mI8dioQBs++Er}7#q9Dck#8fkuCIN10{60m(rOUt3 z6v6CTU89%?^@0fjut(I1DGcEqT|g26Hc>-^>yC47Nsa0abxphrAP;u4sNd$<+#r`3 z3nEK6?80UOhGwv`VWa}IYc8yNqM&+M+vCb>vdJ$_F-BunM;a&=h)91R!a>ymW`j44 zQ-I<)>aarTMhn(s6aO*9jw>VsBuz606=S)EMzOL<`uN-u$115m6JLq|j+Ed4#<3Q1 z09r+w8_$6``c-Q6u0TsNpnpcu2Fz}|;trG>L&Ktt1SyRe^vF;Vs8fZOC+IxdiXG&mV2M>b)0Z@Iw5)jXx<|S8J7npykQM;#`5f^;YnskvFfS!@@G4!0k!PW!@ zf#Dj#re<#Dn$Tmqrh#c1tR70JjW1}Q9W&_%HWN8q6V3a`fdX5Z-6VBP(4iOCBG!JhiAudv_gwT}Wwq@Qa z82khVK$%&ZpQPHSQuu7SmE9E%txMB|09-;D8BXYE%Zh9?4vN$8X0C|V)(~ijw9|(I z!>piaW@7jx+yDRrl1W5CRH6){QZ2J00$IoQ_G@nn7OZSKKMHT;hdb})P%`~iWNEiZ z8z7=xJ<#NlDqkxW_4yp_y2{oWQ1$h!!VopA2d`h0ykR$LjG(DFxod05^&Z4@reF^0 zI6Y(v8~&vDZs_=wtTcrcbC=+8fi&l4zM;0mNs330kQ28ZM$K1{h77k}xcvq%H5xGk z8KDE#SAk{`5FGx|3*e1_R>SpMOk+8H1)3r6k1+uF5=+HgvOX~}mqXsx3tLlwWwj7! z3g7IhYqCY>4Jemm}^I@8EqMG zlbDK>W_}n&Aq~3vHw5vRo6V}&LuyfKO*2lK+1>6y07?c1V6FmCBk!UdUV!DMK*#Hj zFwcRc#IQ(VCYrI-T|{YKpki!!X?4f)qusWL4j?_C;O0kta4#Z9#(~gC44cLgFu%5q ziyqViz>LDn9;mRge6_pj@kJ!G-igbh!61}UsK6duiu6`Ji5)yMIDAs5c;H7|vM>^Y zqiImD#EDp-W3k_A;wZ(v8V0Ft=6*E44OpFj$zfc^r| zV5!I0YUUZvnWA-l%DbaAT#5r4>%nRSkvi0LRHf^(tDl5ZP&J`efzLq<8C3Y#NF8zmuxKQIZE87B6VBF;WKPn8p}ENvQaPL||0ds;{Jx^weOVL)c8LeF)xa3byrPgFteAAJI(}OM>o|3UgN4`pH z*OI_|dFrq~02SPJS^Mcip#TX1tWaP%^(E1~Tjk9a3tBLoh8tZqPf~k5p?IN@NvwJB z3*Jsqi%0uMe6O!|TresI-c>E6?U?wigWi+FEW_M6%@kf|okBJt3fRL6ZTF7t$dpTgs-N Date: Tue, 7 May 2019 21:11:55 +0200 Subject: [PATCH 07/19] Changes to DSC resource PSModule (#450) - A few of localization strings for the DSC resource PSModule was revised to be more descriptive and fixed typos. One localization string was removed as it was not used. --- CHANGELOG.md | 9 +++++++++ .../MSFT_PSModule/en-US/MSFT_PSModule.strings.psd1 | 9 ++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65031e2d..6aa36e57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## Unreleased + +Bug Fixes + +- A few of localization strings for the DSC resource PSModule was revised + to be more descriptive and fixed typos. One localization string was + removed as it was not used. + ## 2.1.2 New Feature @@ -7,6 +15,7 @@ New Feature - Added support for registering repositories with special characters ## 2.1.1 + - Fix DSC resource folder structure ## 2.1.0 diff --git a/DSC/DSCResources/MSFT_PSModule/en-US/MSFT_PSModule.strings.psd1 b/DSC/DSCResources/MSFT_PSModule/en-US/MSFT_PSModule.strings.psd1 index c43e7661..971bf06d 100644 --- a/DSC/DSCResources/MSFT_PSModule/en-US/MSFT_PSModule.strings.psd1 +++ b/DSC/DSCResources/MSFT_PSModule/en-US/MSFT_PSModule.strings.psd1 @@ -25,12 +25,11 @@ ConvertFrom-StringData -StringData @' StartUnInstallModule = Begin invoking Remove-Item to remove the module '{0}' from the file system. InstalledSuccess = Successfully installed the module '{0}' UnInstalledSuccess = Successfully uninstalled the module '{0}' - VersionMismatch = The installed Module '{0}' has the version: '{1}' - RepositoryMismatch = The installed Module '{0}' is from '{1}' repository. + VersionMismatch = The installed module '{0}' has the version: '{1}' + RepositoryMismatch = The installed module '{0}' is from the '{1}' repository. FoundModulePath = Found the module path: '{0}'. - MultipleModuleFound = Total: '{0}' modules found with the same name. Please use -RequiredVersion for filtering. Message: {1} - InstallationPolicyWarning = You are installing the module '{0}' from an untrusted repository' {1}'. Your current InstallationPolicy is '{2}'. If you trust the repository, set the policy to "Trusted". - InstallationPolicyFailed = Failed in the installation policy. Your current InstallationPolicy is '{0}' and the repository is '{1}'. If you trust the repository, set the policy to "Trusted". + InstallationPolicyWarning = The module '{0}' was installed from the untrusted repository' {1}'. The InstallationPolicy is set to '{2}' to override the repository installation policy. If you trust the repository, set the repository installation policy to 'Trusted', that will also remove this warning. + InstallationPolicyFailed = The current installation policy do not allow installation from this repository. Your current installation policy is '{0}' and the repository installation policy is '{1}'. If you trust the repository, either change the repository installation policy, or set the parameter InstallationPolicy to 'Trusted' to override the repository installation policy. GetTargetResourceMessage = Getting the current state of the module '{0}'. TestTargetResourceMessage = Determining if the module '{0}' is in the desired state. '@ From 432b55c31a082eb1997d2f9d7a42f115b6885f05 Mon Sep 17 00:00:00 2001 From: benny1007 <32260961+Benny1007@users.noreply.github.com> Date: Wed, 8 May 2019 03:12:53 +0800 Subject: [PATCH 08/19] fix#191 update publish-module to allow exclude files. (#453) --- Tests/PSGetPublishModule.Tests.ps1 | 2 +- .../functions/Publish-PSArtifactUtility.ps1 | 15 +++++++++++- .../public/psgetfunctions/Publish-Module.ps1 | 23 ++++++++++++------- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/Tests/PSGetPublishModule.Tests.ps1 b/Tests/PSGetPublishModule.Tests.ps1 index 971afdfd..ee6127a8 100644 --- a/Tests/PSGetPublishModule.Tests.ps1 +++ b/Tests/PSGetPublishModule.Tests.ps1 @@ -134,7 +134,7 @@ Describe PowerShell.PSGet.PublishModuleTests -Tags 'BVT','InnerLoop' { # # Expected Result: should be able to publish a module # - It PublishModuleWithNameForSxSVersion { + It "PublishModuleWithNameForSxSVersion" { $version = "2.0.0.0" $semanticVersion = '2.0.0' RemoveItem "$script:PublishModuleBase\*" diff --git a/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 b/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 index 4d93943f..504ae5c0 100644 --- a/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 +++ b/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 @@ -63,7 +63,11 @@ function Publish-PSArtifactUtility { [Parameter(ParameterSetName = 'PublishModule')] [Uri] - $ProjectUri + $ProjectUri, + + [Parameter(ParameterSetName = 'PublishModule')] + [string[]] + $Exclude ) Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -BootstrapNuGetExe @@ -203,6 +207,11 @@ function Publish-PSArtifactUtility { } } + $nuspecFiles = "" + if ($Exclude) { + $nuspecFileExcludePattern = $Exclude -Join ";" + $nuspecFiles = @{ src = "**/*.*"; exclude = $nuspecFileExcludePattern } + } # Add PSModule and PSGet format version tags if (-not $Tags) { @@ -368,6 +377,10 @@ function Publish-PSArtifactUtility { Dependencies = $dependencies } + if ($nuspecFiles) { + $params.Add('Files', $nuspecFiles) + } + try { $NuspecFullName = New-NuspecFile @params } diff --git a/src/PowerShellGet/public/psgetfunctions/Publish-Module.ps1 b/src/PowerShellGet/public/psgetfunctions/Publish-Module.ps1 index 4a3d1f4b..8dec0f20 100644 --- a/src/PowerShellGet/public/psgetfunctions/Publish-Module.ps1 +++ b/src/PowerShellGet/public/psgetfunctions/Publish-Module.ps1 @@ -70,6 +70,11 @@ function Publish-Module { [Uri] $ProjectUri, + [Parameter(ParameterSetName = "ModuleNameParameterSet")] + [ValidateNotNullOrEmpty()] + [string[]] + $Exclude, + [Parameter()] [switch] $Force, @@ -137,8 +142,7 @@ function Publish-Module { if (-not $DestinationLocation -or (-not (Microsoft.PowerShell.Management\Test-Path $DestinationLocation) -and - -not (Test-WebUri -uri $DestinationLocation))) - { + -not (Test-WebUri -uri $DestinationLocation))) { $message = $LocalizedData.PSGalleryPublishLocationIsMissing -f ($Repository, $Repository) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` @@ -370,12 +374,12 @@ function Publish-Module { # This finds all the items without force (leaving out hidden files and dirs) then copies them Microsoft.PowerShell.Management\Get-ChildItem $Path -recurse | Microsoft.PowerShell.Management\Copy-Item -Force -Confirm:$false -WhatIf:$false -Destination { - if ($_.PSIsContainer) { - Join-Path $tempModulePathForFormatVersion $_.Parent.FullName.substring($path.length) - } - else { - join-path $tempModulePathForFormatVersion $_.FullName.Substring($path.Length) - } + if ($_.PSIsContainer) { + Join-Path $tempModulePathForFormatVersion $_.Parent.FullName.substring($path.length) + } + else { + join-path $tempModulePathForFormatVersion $_.FullName.Substring($path.Length) + } } try { @@ -561,6 +565,9 @@ function Publish-Module { if ($PSBoundParameters.Containskey('Credential')) { $PublishPSArtifactUtility_Params.Add('Credential', $Credential) } + if ($Exclude) { + $PublishPSArtifactUtility_Params.Add('Exclude', $Exclude) + } Publish-PSArtifactUtility @PublishPSArtifactUtility_Params } } From 18a9a98df6ea0c67c2bce6f3d0006f8c541a7a51 Mon Sep 17 00:00:00 2001 From: Andrew Wickham Date: Sun, 12 May 2019 15:38:23 -0400 Subject: [PATCH 09/19] Add SkipAutomaticTags Parameter to Publish-Module (#452) * Reusing Tags caused using the Length property to be used like an array instead of string * Added EnforceMaximumTagLength switch on Publish-Module to limit tags to 4000 characters * Renamed EnforceMaximumTagLength to SkipAutomaticTags * Keep Tags as string array and make new variable for a space separated string --- Tests/PSGetPublishModule.Tests.ps1 | 77 +++++++++++++++++++ .../private/functions/New-NuspecFile.ps1 | 9 +-- .../functions/Publish-PSArtifactUtility.ps1 | 76 +++++++++--------- .../public/psgetfunctions/Publish-Module.ps1 | 39 ++++++---- 4 files changed, 144 insertions(+), 57 deletions(-) diff --git a/Tests/PSGetPublishModule.Tests.ps1 b/Tests/PSGetPublishModule.Tests.ps1 index ee6127a8..592ca25e 100644 --- a/Tests/PSGetPublishModule.Tests.ps1 +++ b/Tests/PSGetPublishModule.Tests.ps1 @@ -763,6 +763,83 @@ Describe PowerShell.PSGet.PublishModuleTests -Tags 'BVT','InnerLoop' { } ` -Skip:$($PSVersionTable.PSVersion -lt '5.0.0') + # Purpose: Test Publish-Module cmdlet warns when tag length is greater than 4000 + # + # Action: Create a module manifest with PrivateData\PSData hashtable, try to publish + # + # Expected Result: Publish operation should succeed and should have warned about tag length. + # + It PublishModuleFunctionsAsTagsWarnWithoutSkipAutomaticTags { + $version = "1.0.0" + $Description = "$script:PublishModuleName module" + $Tags = "PSGet","DSC" + $Author = "AuthorName" + $CompanyName = "CompanyName" + $CopyRight = "CopyRight" + + $functionNames = 1..250 | Foreach-Object { "Get-TestFunction$($_)" } + $tempFunctions = 1..250 | Foreach-Object { "function Get-TestFunction$($_) { Get-Date }" + [Environment]::NewLine } + Set-Content (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psm1") -Value $tempFunctions + + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") ` + -ModuleVersion $version ` + -Description "$script:PublishModuleName module" ` + -NestedModules "$script:PublishModuleName.psm1" ` + -Author $Author ` + -CompanyName $CompanyName ` + -Copyright $CopyRight ` + -Tags $Tags ` + -FunctionsToExport $functionNames + + Publish-Module -Path $script:PublishModuleBase ` + -NuGetApiKey $script:ApiKey ` + -Repository "PSGallery" ` + -WarningAction SilentlyContinue ` + -WarningVariable wa + + Assert ("$wa".Contains('4000 characters')) "Warning messages should include 'Tag list exceeded 4000 characters and may not be accepted by some Nuget feeds.'" + } ` + -Skip:$($PSVersionTable.PSVersion -lt '5.0.0') + + # Purpose: Test Publish-Module cmdlet excludes functions from tags when using SkipAutomaticTags parameter + # + # Action: Create a module manifest with PrivateData\PSData hashtable, try to publish with SkipAutomaticTags parameter + # + # Expected Result: Publish operation should succeed and should not have warned about tag length + # + It PublishModuleFunctionsAsTagsWithSkipAutomaticTags { + $version = "1.0.0" + $Description = "$script:PublishModuleName module" + $Tags = "PSGet","DSC" + $Author = "AuthorName" + $CompanyName = "CompanyName" + $CopyRight = "CopyRight" + + $functionNames = 1..250 | Foreach-Object { "Get-TestFunction$($_)" } + $tempFunctions = 1..250 | Foreach-Object { "function Get-TestFunction$($_) { Get-Date }" + [Environment]::NewLine } + Set-Content (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psm1") -Value $tempFunctions + + New-ModuleManifest -Path (Join-Path -Path $script:PublishModuleBase -ChildPath "$script:PublishModuleName.psd1") ` + -ModuleVersion $version ` + -Description "$script:PublishModuleName module" ` + -NestedModules "$script:PublishModuleName.psm1" ` + -Author $Author ` + -CompanyName $CompanyName ` + -Copyright $CopyRight ` + -Tags $Tags ` + -FunctionsToExport $functionNames + + Publish-Module -Path $script:PublishModuleBase ` + -NuGetApiKey $script:ApiKey ` + -Repository "PSGallery" ` + -SkipAutomaticTags ` + -WarningAction SilentlyContinue ` + -WarningVariable wa + + Assert (-not "$wa".Contains('4000 characters')) "Warning messages should not include 'Tag list exceeded 4000 characters and may not be accepted by some Nuget feeds.'" + } ` + -Skip:$($PSVersionTable.PSVersion -lt '5.0.0') + # Purpose: Test Publish-Module cmdlet gets the PSData properties from the module manifest file and also with Uri objects specified to the cmdlet # # Action: Create a module manifest with PrivateData\PSData hashtable, try to publish it with Uri objects to ProjectUri, IconUri and LicenseUri parameters diff --git a/src/PowerShellGet/private/functions/New-NuspecFile.ps1 b/src/PowerShellGet/private/functions/New-NuspecFile.ps1 index e071d20e..767afc52 100644 --- a/src/PowerShellGet/private/functions/New-NuspecFile.ps1 +++ b/src/PowerShellGet/private/functions/New-NuspecFile.ps1 @@ -59,10 +59,9 @@ function New-NuspecFile { $packageElement = $xml.CreateElement("package", $nameSpaceUri) $metaDataElement = $xml.CreateElement("metadata", $nameSpaceUri) - #truncate tags if they exceed nuspec specifications for size. - $Tags = $Tags -Join " " - - if ($Tags.Length -gt 4000) { + # warn we're over 4000 characters for standard nuget servers + $tagsString = $Tags -Join " " + if ($tagsString.Length -gt 4000) { Write-Warning -Message "Tag list exceeded 4000 characters and may not be accepted by some Nuget feeds." } @@ -75,7 +74,7 @@ function New-NuspecFile { releaseNotes = $ReleaseNotes requireLicenseAcceptance = $RequireLicenseAcceptance.ToString().ToLower() copyright = $Copyright - tags = $Tags + tags = $tagsString } if ($LicenseUrl) { $metaDataElementsHash.Add("licenseUrl", $LicenseUrl) } diff --git a/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 b/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 index 504ae5c0..4d7b5e6d 100644 --- a/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 +++ b/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 @@ -53,6 +53,10 @@ function Publish-PSArtifactUtility { [string[]] $Tags, + [Parameter(ParameterSetName = 'PublishModule')] + [switch] + $SkipAutomaticTags, + [Parameter(ParameterSetName = 'PublishModule')] [Uri] $LicenseUri, @@ -227,7 +231,7 @@ function Publish-PSArtifactUtility { if ($PSScriptInfo) { $Tags += "PSScript" - if ($PSScriptInfo.DefinedCommands) { + if ($PSScriptInfo.DefinedCommands -and -not $SkipAutomaticTags) { if ($PSScriptInfo.DefinedFunctions) { $Tags += "$($script:Includes)_Function" $Tags += $PSScriptInfo.DefinedFunctions | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Function)_$_" } @@ -260,52 +264,54 @@ function Publish-PSArtifactUtility { $ModuleManifestHashTable = Get-ManifestHashTable -Path $ManifestPath - if ($PSModuleInfo.ExportedCommands.Count) { - if ($PSModuleInfo.ExportedCmdlets.Count) { - $Tags += "$($script:Includes)_Cmdlet" - $Tags += $PSModuleInfo.ExportedCmdlets.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Cmdlet)_$_" } + if (-not $SkipAutomaticTags) { + if ($PSModuleInfo.ExportedCommands.Count) { + if ($PSModuleInfo.ExportedCmdlets.Count) { + $Tags += "$($script:Includes)_Cmdlet" + $Tags += $PSModuleInfo.ExportedCmdlets.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Cmdlet)_$_" } - #if CmdletsToExport field in manifest file is "*", we suggest the user to include all those cmdlets for best practice - if ($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey('CmdletsToExport') -and ($ModuleManifestHashTable.CmdletsToExport -eq "*")) { - $WarningMessage = $LocalizedData.ShouldIncludeCmdletsToExport -f ($ManifestPath) - Write-Warning -Message $WarningMessage + #if CmdletsToExport field in manifest file is "*", we suggest the user to include all those cmdlets for best practice + if ($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey('CmdletsToExport') -and ($ModuleManifestHashTable.CmdletsToExport -eq "*")) { + $WarningMessage = $LocalizedData.ShouldIncludeCmdletsToExport -f ($ManifestPath) + Write-Warning -Message $WarningMessage + } } - } - if ($PSModuleInfo.ExportedFunctions.Count) { - $Tags += "$($script:Includes)_Function" - $Tags += $PSModuleInfo.ExportedFunctions.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Function)_$_" } + if ($PSModuleInfo.ExportedFunctions.Count) { + $Tags += "$($script:Includes)_Function" + $Tags += $PSModuleInfo.ExportedFunctions.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Function)_$_" } - if ($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey('FunctionsToExport') -and ($ModuleManifestHashTable.FunctionsToExport -eq "*")) { - $WarningMessage = $LocalizedData.ShouldIncludeFunctionsToExport -f ($ManifestPath) - Write-Warning -Message $WarningMessage + if ($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey('FunctionsToExport') -and ($ModuleManifestHashTable.FunctionsToExport -eq "*")) { + $WarningMessage = $LocalizedData.ShouldIncludeFunctionsToExport -f ($ManifestPath) + Write-Warning -Message $WarningMessage + } } - } - $Tags += $PSModuleInfo.ExportedCommands.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Command)_$_" } - } + $Tags += $PSModuleInfo.ExportedCommands.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Command)_$_" } + } - $dscResourceNames = Get-ExportedDscResources -PSModuleInfo $PSModuleInfo - if ($dscResourceNames) { - $Tags += "$($script:Includes)_DscResource" + $dscResourceNames = Get-ExportedDscResources -PSModuleInfo $PSModuleInfo + if ($dscResourceNames) { + $Tags += "$($script:Includes)_DscResource" - $Tags += $dscResourceNames | Microsoft.PowerShell.Core\ForEach-Object { "$($script:DscResource)_$_" } + $Tags += $dscResourceNames | Microsoft.PowerShell.Core\ForEach-Object { "$($script:DscResource)_$_" } - #If DscResourcesToExport is commented out or "*" is used, we will write-warning - if ($ModuleManifestHashTable -and - ($ModuleManifestHashTable.ContainsKey("DscResourcesToExport") -and - $ModuleManifestHashTable.DscResourcesToExport -eq "*") -or - -not $ModuleManifestHashTable.ContainsKey("DscResourcesToExport")) { - $WarningMessage = $LocalizedData.ShouldIncludeDscResourcesToExport -f ($ManifestPath) - Write-Warning -Message $WarningMessage + #If DscResourcesToExport is commented out or "*" is used, we will write-warning + if ($ModuleManifestHashTable -and + ($ModuleManifestHashTable.ContainsKey("DscResourcesToExport") -and + $ModuleManifestHashTable.DscResourcesToExport -eq "*") -or + -not $ModuleManifestHashTable.ContainsKey("DscResourcesToExport")) { + $WarningMessage = $LocalizedData.ShouldIncludeDscResourcesToExport -f ($ManifestPath) + Write-Warning -Message $WarningMessage + } } - } - $RoleCapabilityNames = Get-AvailableRoleCapabilityName -PSModuleInfo $PSModuleInfo - if ($RoleCapabilityNames) { - $Tags += "$($script:Includes)_RoleCapability" + $RoleCapabilityNames = Get-AvailableRoleCapabilityName -PSModuleInfo $PSModuleInfo + if ($RoleCapabilityNames) { + $Tags += "$($script:Includes)_RoleCapability" - $Tags += $RoleCapabilityNames | Microsoft.PowerShell.Core\ForEach-Object { "$($script:RoleCapability)_$_" } + $Tags += $RoleCapabilityNames | Microsoft.PowerShell.Core\ForEach-Object { "$($script:RoleCapability)_$_" } + } } # Populate the module dependencies elements from RequiredModules and diff --git a/src/PowerShellGet/public/psgetfunctions/Publish-Module.ps1 b/src/PowerShellGet/public/psgetfunctions/Publish-Module.ps1 index 8dec0f20..f0fd6776 100644 --- a/src/PowerShellGet/public/psgetfunctions/Publish-Module.ps1 +++ b/src/PowerShellGet/public/psgetfunctions/Publish-Module.ps1 @@ -81,7 +81,11 @@ function Publish-Module { [Parameter(ParameterSetName = "ModuleNameParameterSet")] [switch] - $AllowPrerelease + $AllowPrerelease, + + [Parameter()] + [switch] + $SkipAutomaticTags ) Begin { @@ -545,22 +549,23 @@ function Publish-Module { $shouldProcessMessage = $LocalizedData.PublishModulewhatIfMessage -f ($moduleInfo.Version, $moduleInfo.Name) if ($Force -or $PSCmdlet.ShouldProcess($shouldProcessMessage, "Publish-Module")) { $PublishPSArtifactUtility_Params = @{ - PSModuleInfo = $moduleInfo - ManifestPath = $manifestPath - NugetApiKey = $NuGetApiKey - Destination = $DestinationLocation - Repository = $Repository - NugetPackageRoot = $tempModulePath - FormatVersion = $FormatVersion - ReleaseNotes = $($ReleaseNotes -join "`r`n") - Tags = $Tags - LicenseUri = $LicenseUri - IconUri = $IconUri - ProjectUri = $ProjectUri - Verbose = $VerbosePreference - WarningAction = $WarningPreference - ErrorAction = $ErrorActionPreference - Debug = $DebugPreference + PSModuleInfo = $moduleInfo + ManifestPath = $manifestPath + NugetApiKey = $NuGetApiKey + Destination = $DestinationLocation + Repository = $Repository + NugetPackageRoot = $tempModulePath + FormatVersion = $FormatVersion + ReleaseNotes = $($ReleaseNotes -join "`r`n") + Tags = $Tags + SkipAutomaticTags = $SkipAutomaticTags + LicenseUri = $LicenseUri + IconUri = $IconUri + ProjectUri = $ProjectUri + Verbose = $VerbosePreference + WarningAction = $WarningPreference + ErrorAction = $ErrorActionPreference + Debug = $DebugPreference } if ($PSBoundParameters.Containskey('Credential')) { $PublishPSArtifactUtility_Params.Add('Credential', $Credential) From c3e0d7d4601245625913594caf9bd7f1c357b222 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Mon, 13 May 2019 14:20:11 -0700 Subject: [PATCH 10/19] Add -Force to Get-ChildItem params (#476) --- .../private/functions/Set-InstalledModulesVariable.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PowerShellGet/private/functions/Set-InstalledModulesVariable.ps1 b/src/PowerShellGet/private/functions/Set-InstalledModulesVariable.ps1 index 04a77f0d..9c358aac 100644 --- a/src/PowerShellGet/private/functions/Set-InstalledModulesVariable.ps1 +++ b/src/PowerShellGet/private/functions/Set-InstalledModulesVariable.ps1 @@ -11,6 +11,7 @@ function Set-InstalledModulesVariable $GetChildItemParams = @{ Path = $location Recurse = $true + Force = $true Filter = $script:PSGetItemInfoFileName ErrorAction = 'SilentlyContinue' WarningAction = 'SilentlyContinue' From 23797a9c0bca77075006b373ef0f8ec9557e7999 Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Mon, 13 May 2019 15:42:35 -0700 Subject: [PATCH 11/19] Update module version and changelog (#477) --- CHANGELOG.md | 16 ++++++++++------ src/PowerShellGet/PowerShellGet.psd1 | 15 +++++++++++++-- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6aa36e57..95d3478c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,18 +1,22 @@ # Changelog -## Unreleased +## 2.1.3 -Bug Fixes +New Features + +- Added -Scope parameter to Update-Module (Thanks @lwajswaj!) (#471) +- Added -Exclude parameter to Publish-Module (Thanks @Benny1007!) (#191) +- Added -SkipAutomticTags parameter to Publish-Module (Thanks @awickham10!) (#452) + +Bug Fix -- A few of localization strings for the DSC resource PSModule was revised - to be more descriptive and fixed typos. One localization string was - removed as it was not used. +- Fixed issue with finding modules using macOS and .NET Core 3.0 ## 2.1.2 New Feature -- Added support for registering repositories with special characters +- Added support for registering repositories with special characters (@Thanks jborean93!) (#442) ## 2.1.1 diff --git a/src/PowerShellGet/PowerShellGet.psd1 b/src/PowerShellGet/PowerShellGet.psd1 index 4d50574d..a89c8f76 100644 --- a/src/PowerShellGet/PowerShellGet.psd1 +++ b/src/PowerShellGet/PowerShellGet.psd1 @@ -1,6 +1,6 @@ @{ RootModule = 'PSModule.psm1' - ModuleVersion = '2.1.2' + ModuleVersion = '2.1.3' GUID = '1d73a601-4a6c-43c5-ba3f-619b18bbb404' Author = 'Microsoft Corporation' CompanyName = 'Microsoft Corporation' @@ -40,7 +40,7 @@ FileList = @('PSModule.psm1', 'PSGet.Format.ps1xml', 'PSGet.Resource.psd1') - RequiredModules = @(@{ModuleName = 'PackageManagement'; ModuleVersion = '1.1.7.0'}) + RequiredModules = @(@{ModuleName = 'PackageManagement'; ModuleVersion = '1.1.7.0' }) PrivateData = @{ "PackageManagementProviders" = 'PSModule.psm1' "SupportedPowerShellGetFormatVersions" = @('1.x', '2.x') @@ -54,6 +54,17 @@ ProjectUri = 'https://go.microsoft.com/fwlink/?LinkId=828955' LicenseUri = 'https://go.microsoft.com/fwlink/?LinkId=829061' ReleaseNotes = @' +## 2.1.3 +New Features + +- Added -Scope parameter to Update-Module (Thanks @lwajswaj!) (#471) +- Added -Exclude parameter to Publish-Module (Thanks @Benny1007!) (#191) +- Added -SkipAutomticTags parameter to Publish-Module (Thanks @awickham10!) (#452) + +Bug Fix + +- Fixed issue with finding modules using macOS and .NET Core 3.0 + ## 2.1.2 New Feature From 7de99ee0c38611556e5c583ffaca98bb1922a0d4 Mon Sep 17 00:00:00 2001 From: Edwin Young Date: Fri, 17 May 2019 09:04:32 -0700 Subject: [PATCH 12/19] fix new-nugetpackage to cope with more output from child process (#479) * fix new-nugetpackage to cope with more output from child process * address PR feedback --- .../private/functions/New-NugetPackage.ps1 | 111 ++++++++++-------- .../private/functions/New-NuspecFile.ps1 | 2 + .../functions/Publish-NugetPackage.ps1 | 1 + .../functions/Publish-PSArtifactUtility.ps1 | 1 + 4 files changed, 64 insertions(+), 51 deletions(-) diff --git a/src/PowerShellGet/private/functions/New-NugetPackage.ps1 b/src/PowerShellGet/private/functions/New-NugetPackage.ps1 index 16cd6502..c4d773ab 100644 --- a/src/PowerShellGet/private/functions/New-NugetPackage.ps1 +++ b/src/PowerShellGet/private/functions/New-NugetPackage.ps1 @@ -19,6 +19,8 @@ function New-NugetPackage { ) Set-StrictMode -Off + Write-Verbose "Calling New-NugetPackage" + if (-Not(Test-Path -Path $NuspecPath -PathType Leaf)) { throw "A nuspec file does not exist at $NuspecPath, provide valid path to a .nuspec" } @@ -27,89 +29,96 @@ function New-NugetPackage { throw "NugetPackageRoot $NugetPackageRoot does not exist" } + $processStartInfo = New-Object System.Diagnostics.ProcessStartInfo if ($PSCmdlet.ParameterSetName -eq "UseNuget") { if (-Not(Test-Path -Path $NuGetExePath)) { throw "Nuget.exe does not exist at $NugetExePath, provide a valid path to nuget.exe" } + $ProcessName = $NugetExePath $ArgumentList = @("pack") $ArgumentList += "`"$NuspecPath`"" - $ArgumentList += "-outputdirectory `"$OutputPath`"" - - $processStartInfo = New-Object System.Diagnostics.ProcessStartInfo - $processStartInfo.FileName = $NugetExePath - $processStartInfo.RedirectStandardError = $true - $processStartInfo.RedirectStandardOutput = $true - $processStartInfo.UseShellExecute = $false - $processStartInfo.Arguments = $ArgumentList - - $process = New-Object System.Diagnostics.Process - $process.StartInfo = $processStartInfo - $process.Start() | Out-Null - $process.WaitForExit() - - if (-Not ($process.ExitCode -eq 0 )) { - $stdErr = $process.StandardError.ReadToEnd() - throw "nuget.exe failed to pack $stdErr" - } + $ArgumentList += "-outputdirectory `"$OutputPath`" -noninteractive" + + $tempPath = $null } + else { + # use Dotnet CLI - if ($PSCmdlet.ParameterSetName -eq "UseDotnetCli") { #perform dotnet pack using a temporary project file. - $dotnetCliPath = (Get-Command -Name "dotnet").Source + $ProcessName = (Get-Command -Name "dotnet").Source $tempPath = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath ([System.Guid]::NewGuid()).Guid New-Item -ItemType Directory -Path $tempPath -Force | Out-Null $CsprojContent = @" - - - NotUsed - Temp project used for creating nupkg file. - netcoreapp2.0 - true - - + + + NotUsed + Temp project used for creating nupkg file. + netcoreapp2.0 + true + + "@ $projectFile = New-Item -ItemType File -Path $tempPath -Name "Temp.csproj" Set-Content -Value $CsprojContent -Path $projectFile - #execution - $ArgumentList = @("pack") $ArgumentList += "`"$projectFile`"" $ArgumentList += "/p:NuspecFile=`"$NuspecPath`"" $ArgumentList += "--output `"$OutputPath`"" + } - $processStartInfo = New-Object System.Diagnostics.ProcessStartInfo - $processStartInfo.FileName = $dotnetCliPath - $processStartInfo.RedirectStandardError = $true - $processStartInfo.RedirectStandardOutput = $true - $processStartInfo.UseShellExecute = $false - $processStartInfo.Arguments = $ArgumentList + # run the packing program + $processStartInfo = New-Object System.Diagnostics.ProcessStartInfo + $processStartInfo.FileName = $ProcessName + $processStartInfo.Arguments = $ArgumentList + $processStartInfo.RedirectStandardError = $true + $processStartInfo.RedirectStandardOutput = $true + $processStartInfo.UseShellExecute = $false + + Write-Verbose "Calling $ProcessName $($ArgumentList -join ' ')" + $process = New-Object System.Diagnostics.Process + $process.StartInfo = $processStartInfo + + $process.Start() | Out-Null + + # read output incrementally, it'll block if it writes too much + $outputLines = @() + Write-Verbose "$ProcessName output:" + while (! $process.HasExited) { + $output = $process.StandardOutput.ReadLine() + Write-Verbose "`t$output" + $outputLines += $output + } - $process = New-Object System.Diagnostics.Process - $process.StartInfo = $processStartInfo - $process.Start() | Out-Null - $process.WaitForExit() + # get any remaining output + $process.WaitForExit() + $outputLines += $process.StandardOutput.ReadToEnd() - if (Test-Path -Path $tempPath) { - Remove-Item -Path $tempPath -Force -Recurse - } + $stdOut = $outputLines -join "`n" - if (-Not ($process.ExitCode -eq 0 )) { - $stdOut = $process.StandardOutput.ReadToEnd() - throw "dotnet cli failed to pack $stdOut" - } + Write-Verbose "finished running $($processStartInfo.FileName) with exit code $($process.ExitCode)" + + if (($tempPath -ne $null) -and (Test-Path -Path $tempPath)) { + Remove-Item -Path $tempPath -Force -Recurse + } + if (-Not ($process.ExitCode -eq 0 )) { + # nuget writes errors to stdErr, dotnet writes them to stdOut + if ($UseDotnetCli) { + $errors = $stdOut + } + else { + $errors = $process.StandardError.ReadToEnd() + } + throw "$ProcessName failed to pack: error $errors" } - $stdOut = $process.StandardOutput.ReadToEnd() $stdOut -match "Successfully created package '(.*.nupkg)'" | Out-Null $nupkgFullFile = $matches[1] - $stdOut = $process.StandardOutput.ReadToEnd() - - Write-Verbose -Message $stdOut + Write-Verbose "Created Nuget Package $nupkgFullFile" Write-Output $nupkgFullFile } diff --git a/src/PowerShellGet/private/functions/New-NuspecFile.ps1 b/src/PowerShellGet/private/functions/New-NuspecFile.ps1 index 767afc52..62f26a30 100644 --- a/src/PowerShellGet/private/functions/New-NuspecFile.ps1 +++ b/src/PowerShellGet/private/functions/New-NuspecFile.ps1 @@ -49,6 +49,8 @@ function New-NuspecFile { ) Set-StrictMode -Off + Write-Verbose "Calling New-NuspecFile" + $nameSpaceUri = "http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd" [xml]$xml = New-Object System.Xml.XmlDocument diff --git a/src/PowerShellGet/private/functions/Publish-NugetPackage.ps1 b/src/PowerShellGet/private/functions/Publish-NugetPackage.ps1 index d410bd30..d470dba4 100644 --- a/src/PowerShellGet/private/functions/Publish-NugetPackage.ps1 +++ b/src/PowerShellGet/private/functions/Publish-NugetPackage.ps1 @@ -18,6 +18,7 @@ function Publish-NugetPackage { ) Set-StrictMode -Off + Write-Verbose "Calling Publish-NugetPackage -NupkgPath $NupkgPath -Destination $Destination -NugetExePath $NugetExePath -UseDotnetCli:$UseDotnetCli" $Destination = $Destination.TrimEnd("\") if ($PSCmdlet.ParameterSetName -eq "UseNuget") { diff --git a/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 b/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 index 4d7b5e6d..82481442 100644 --- a/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 +++ b/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 @@ -74,6 +74,7 @@ function Publish-PSArtifactUtility { $Exclude ) + Write-Verbose "Calling Publish-PSArtifactUtility" Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -BootstrapNuGetExe $PSArtifactType = $script:PSArtifactTypeModule From 95eef98e14c9c06196ca2b0bb34316b6d68d6ad8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hei=C3=B0ar=20H=C3=B3lmberg=20J=C3=B3nsson?= Date: Tue, 21 May 2019 09:37:43 +0000 Subject: [PATCH 13/19] Catch nuget error and diplay localized error instead --- .../private/functions/Publish-PSArtifactUtility.ps1 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 b/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 index b5571a54..3c3bffe2 100644 --- a/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 +++ b/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 @@ -585,6 +585,11 @@ $CsprojContent = @" $errorMsg = $LocalizedData.RegisterVSTSFeedAsNuGetPackageSource -f ($Destination, $script:VSTSAuthenticatedFeedsDocUrl) } + if($errorMsg -match 'warn : No API Key was provided and no API Key could be found for *') + { + $errorMsg = $LocalizedData.NuGetApiKeyIsRequiredForNuGetBasedGalleryService -f ($Name, $Destination) + } + if($PSArtifactType -eq $script:PSArtifactTypeModule) { $message = $LocalizedData.FailedToPublish -f ($Name,$errorMsg) From 1aade962fcf2ab6852a69c8eaf11036d61e05e8b Mon Sep 17 00:00:00 2001 From: Edwin Young Date: Tue, 21 May 2019 13:04:41 -0700 Subject: [PATCH 14/19] Update version, packagemanagement dependency version, and changelog (#480) --- CHANGELOG.md | 6 ++++++ src/PowerShellGet/PowerShellGet.psd1 | 10 +++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95d3478c..60be57c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 2.1.4 + +Bug Fix + +- Fixed hang when publishing some modules (#478) + ## 2.1.3 New Features diff --git a/src/PowerShellGet/PowerShellGet.psd1 b/src/PowerShellGet/PowerShellGet.psd1 index a89c8f76..18e95b6a 100644 --- a/src/PowerShellGet/PowerShellGet.psd1 +++ b/src/PowerShellGet/PowerShellGet.psd1 @@ -1,6 +1,6 @@ @{ RootModule = 'PSModule.psm1' - ModuleVersion = '2.1.3' + ModuleVersion = '2.1.4' GUID = '1d73a601-4a6c-43c5-ba3f-619b18bbb404' Author = 'Microsoft Corporation' CompanyName = 'Microsoft Corporation' @@ -40,7 +40,7 @@ FileList = @('PSModule.psm1', 'PSGet.Format.ps1xml', 'PSGet.Resource.psd1') - RequiredModules = @(@{ModuleName = 'PackageManagement'; ModuleVersion = '1.1.7.0' }) + RequiredModules = @(@{ModuleName = 'PackageManagement'; ModuleVersion = '1.3.2' }) PrivateData = @{ "PackageManagementProviders" = 'PSModule.psm1' "SupportedPowerShellGetFormatVersions" = @('1.x', '2.x') @@ -54,12 +54,16 @@ ProjectUri = 'https://go.microsoft.com/fwlink/?LinkId=828955' LicenseUri = 'https://go.microsoft.com/fwlink/?LinkId=829061' ReleaseNotes = @' + +## 2.1.4 +- Fixed hang while publishing some packages (#478) + ## 2.1.3 New Features - Added -Scope parameter to Update-Module (Thanks @lwajswaj!) (#471) - Added -Exclude parameter to Publish-Module (Thanks @Benny1007!) (#191) -- Added -SkipAutomticTags parameter to Publish-Module (Thanks @awickham10!) (#452) +- Added -SkipAutomaticTags parameter to Publish-Module (Thanks @awickham10!) (#452) Bug Fix From 0f667f29a4cecd9b8abee1a4df63b2c31f7a753a Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Tue, 21 May 2019 14:20:43 -0700 Subject: [PATCH 15/19] Dependency update (#483) --- src/PowerShellGet/PowerShellGet.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PowerShellGet/PowerShellGet.psd1 b/src/PowerShellGet/PowerShellGet.psd1 index 18e95b6a..f2babb35 100644 --- a/src/PowerShellGet/PowerShellGet.psd1 +++ b/src/PowerShellGet/PowerShellGet.psd1 @@ -40,7 +40,7 @@ FileList = @('PSModule.psm1', 'PSGet.Format.ps1xml', 'PSGet.Resource.psd1') - RequiredModules = @(@{ModuleName = 'PackageManagement'; ModuleVersion = '1.3.2' }) + RequiredModules = @(@{ModuleName = 'PackageManagement'; ModuleVersion = '1.4' }) PrivateData = @{ "PackageManagementProviders" = 'PSModule.psm1' "SupportedPowerShellGetFormatVersions" = @('1.x', '2.x') From bfc528469ecbdc8ba1023680e2fd4566143d9d7b Mon Sep 17 00:00:00 2001 From: alerickson <25858831+alerickson@users.noreply.github.com> Date: Wed, 13 Mar 2019 17:37:26 -0700 Subject: [PATCH 16/19] Merge development to master (#440) --- SignConfig.xml | 2 +- src/PowerShellGet/PowerShellGet.psd1 | 162 +++++++++++++-------------- 2 files changed, 82 insertions(+), 82 deletions(-) diff --git a/SignConfig.xml b/SignConfig.xml index 071e8b31..cce952dc 100644 --- a/SignConfig.xml +++ b/SignConfig.xml @@ -21,4 +21,4 @@ - \ No newline at end of file + diff --git a/src/PowerShellGet/PowerShellGet.psd1 b/src/PowerShellGet/PowerShellGet.psd1 index f2babb35..43ba70ac 100644 --- a/src/PowerShellGet/PowerShellGet.psd1 +++ b/src/PowerShellGet/PowerShellGet.psd1 @@ -1,59 +1,59 @@ @{ - RootModule = 'PSModule.psm1' - ModuleVersion = '2.1.4' - GUID = '1d73a601-4a6c-43c5-ba3f-619b18bbb404' - Author = 'Microsoft Corporation' - CompanyName = 'Microsoft Corporation' - Copyright = '(c) Microsoft Corporation. All rights reserved.' - Description = 'PowerShell module with commands for discovering, installing, updating and publishing the PowerShell artifacts like Modules, DSC Resources, Role Capabilities and Scripts.' - PowerShellVersion = '3.0' - FormatsToProcess = 'PSGet.Format.ps1xml' - FunctionsToExport = @( - 'Find-Command', - 'Find-DSCResource', - 'Find-Module', - 'Find-RoleCapability', - 'Find-Script', - 'Get-InstalledModule', - 'Get-InstalledScript', - 'Get-PSRepository', - 'Install-Module', - 'Install-Script', - 'New-ScriptFileInfo', - 'Publish-Module', - 'Publish-Script', - 'Register-PSRepository', - 'Save-Module', - 'Save-Script', - 'Set-PSRepository', - 'Test-ScriptFileInfo', - 'Uninstall-Module', - 'Uninstall-Script', - 'Unregister-PSRepository', - 'Update-Module', - 'Update-ModuleManifest', - 'Update-Script', - 'Update-ScriptFileInfo') - - VariablesToExport = "*" - AliasesToExport = @('inmo', 'fimo', 'upmo', 'pumo') - FileList = @('PSModule.psm1', - 'PSGet.Format.ps1xml', - 'PSGet.Resource.psd1') - RequiredModules = @(@{ModuleName = 'PackageManagement'; ModuleVersion = '1.4' }) - PrivateData = @{ - "PackageManagementProviders" = 'PSModule.psm1' - "SupportedPowerShellGetFormatVersions" = @('1.x', '2.x') - PSData = @{ - Tags = @('Packagemanagement', - 'Provider', - 'PSEdition_Desktop', - 'PSEdition_Core', - 'Linux', - 'Mac') - ProjectUri = 'https://go.microsoft.com/fwlink/?LinkId=828955' - LicenseUri = 'https://go.microsoft.com/fwlink/?LinkId=829061' - ReleaseNotes = @' + RootModule = 'PSModule.psm1' + ModuleVersion = '2.1.4' + Description = 'PowerShell module with commands for discovering, installing, updating and publishing the PowerShell artifacts like Modules, DSC Resources, Role Capabilities and Scripts.' + PowerShellVersion = '3.0' + FormatsToProcess = 'PSGet.Format.ps1xml' + FunctionsToExport = @( + 'Find-Command', + 'Find-DSCResource', + 'Find-Module', + 'Find-RoleCapability', + 'Find-Script', + 'Get-InstalledModule', + 'Get-InstalledScript', + 'Get-PSRepository', + 'Install-Module', + 'Install-Script', + 'New-ScriptFileInfo', + 'Publish-Module', + 'Publish-Script', + 'Register-PSRepository', + 'Save-Module', + 'Save-Script', + 'Set-PSRepository', + 'Test-ScriptFileInfo', + 'Uninstall-Module', + 'Uninstall-Script', + 'Unregister-PSRepository', + 'Update-Module', + 'Update-ModuleManifest', + 'Update-Script', + 'Update-ScriptFileInfo') + + VariablesToExport = "*" + AliasesToExport = @('inmo', 'fimo', 'upmo', 'pumo') + FileList = @('PSModule.psm1', + 'PSGet.Format.ps1xml', + 'PSGet.Resource.psd1') + RequiredModules = @(@{ModuleName = 'PackageManagement'; ModuleVersion = '1.1.7.0' }) + PrivateData = @{ + "PackageManagementProviders" = 'PSModule.psm1' + "SupportedPowerShellGetFormatVersions" = @('1.x', '2.x') + RequiredModules = @(@{ModuleName = 'PackageManagement'; ModuleVersion = '1.4' }) + 'Linux', + 'Mac') + ProjectUri = 'https://go.microsoft.com/fwlink/?LinkId=828955' + LicenseUri = 'https://go.microsoft.com/fwlink/?LinkId=829061' + ReleaseNotes = @' +## 2.1.2 + +New Feature + +- Added support for registering repositories with special characters + +## 2.1.1 + ## 2.1.4 - Fixed hang while publishing some packages (#478) @@ -75,32 +75,6 @@ New Feature - Added support for registering repositories with special characters -## 2.1.1 - -- Fix DSC resource folder structure - -## 2.1.0 - -Breaking Change - -- Default installation scope for Update-Module and Update-Script has changed to match Install-Module and Install-Script. For Windows PowerShell (version 5.1 or below), the default scope is AllUsers when running in an elevated session, and CurrentUser at all other times. - For PowerShell version 6.0.0 and above, the default installation scope is always CurrentUser. (#421) - -Bug Fixes - -- Update-ModuleManifest no longer clears FunctionsToExport, AliasesToExport, nor NestModules (#415 & #425) (Thanks @pougetat and @tnieto88!) -- Update-Module no longer changes repository URL (#407) -- Update-ModuleManifest no longer preprends 'PSGet_' to module name (#403) (Thanks @ThePoShWolf) -- Update-ModuleManifest now throws error and fails to update when provided invalid entries (#398) (Thanks @pougetat!) -- Ignore files no longer being included when uploading modules (#396) - -New Features - -- New DSC resource, PSRepository (#426) (Thanks @johlju!) -- Piping of PS respositories (#420) -- utf8 support for .nuspec (#419) - -## 2.0.4 Bug Fix * Remove PSGallery availability checks (#374) @@ -250,6 +224,32 @@ Bug fixes * Fixed '[Test-ScriptFileInfo] Fails on *NIX newlines (LF vs. CRLF)' (#18) +## 1.1.1.0 + +Bug fixes +* Fixed 'Update-Module fails with `ModuleAuthenticodeSignature` error for modules with signed PSD1'. (#12) (#8) +* Fixed 'Properties of `AdditionalMetadata` are case-sensitive'. #7 +* Changed `ErrorAction` to `Ignore` for few cmdlet usages as they should not show up in ErrorVariable. + - For example, error returned by `Get-Command Test-FileCatalog` should be ignored. + + +## 1.1.0.0 + +* Initial release from GitHub. +* PowerShellCore support. +* Security enhancements including the enforcement of catalog-signed modules during installation. +* Authenticated Repository support. +* Proxy Authentication support. +* Responses to a number of user requests and issues. +'@ +} +} + +HelpInfoURI = 'http://go.microsoft.com/fwlink/?linkid=855963' +} +* Fixed '[Test-ScriptFileInfo] Fails on *NIX newlines (LF vs. CRLF)' (#18) + + ## 1.1.1.0 Bug fixes From 89ff9c596ed54c94e5c2b6ea9297b5b128d154e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hei=C3=B0ar=20H=C3=B3lmberg=20J=C3=B3nsson?= Date: Fri, 12 Apr 2019 11:18:01 +0000 Subject: [PATCH 17/19] Remove validation on NugetApiKey parameter Removed _ValidateNotNullOrEmpty_ from NugetApiKey and implemented checking for the parameter in Publish-Module and Publish-PSArtifactUtility similar to how credentials are added conditionally. --- .../functions/Publish-PSArtifactUtility.ps1 | 938 +++++++++--------- .../public/psgetfunctions/Publish-Module.ps1 | 38 +- 2 files changed, 504 insertions(+), 472 deletions(-) diff --git a/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 b/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 index 82481442..009cd5ff 100644 --- a/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 +++ b/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 @@ -1,458 +1,482 @@ function Publish-PSArtifactUtility { - [CmdletBinding(PositionalBinding = $false)] - Param - ( - [Parameter(Mandatory = $true, ParameterSetName = 'PublishModule')] - [ValidateNotNullOrEmpty()] - [PSModuleInfo] - $PSModuleInfo, - - [Parameter(Mandatory = $true, ParameterSetName = 'PublishScript')] - [ValidateNotNullOrEmpty()] - [PSCustomObject] - $PSScriptInfo, - - [Parameter(Mandatory = $true, ParameterSetName = 'PublishModule')] - [ValidateNotNullOrEmpty()] - [string] - $ManifestPath, - - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] - $Destination, - - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] - $Repository, - - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] - $NugetApiKey, - - [Parameter(Mandatory = $false)] - [pscredential] - $Credential, - - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] - $NugetPackageRoot, - - [Parameter(ParameterSetName = 'PublishModule')] - [Version] - $FormatVersion, - - [Parameter(ParameterSetName = 'PublishModule')] - [string] - $ReleaseNotes, - - [Parameter(ParameterSetName = 'PublishModule')] - [string[]] - $Tags, - - [Parameter(ParameterSetName = 'PublishModule')] - [switch] - $SkipAutomaticTags, - - [Parameter(ParameterSetName = 'PublishModule')] - [Uri] - $LicenseUri, - - [Parameter(ParameterSetName = 'PublishModule')] - [Uri] - $IconUri, - - [Parameter(ParameterSetName = 'PublishModule')] - [Uri] - $ProjectUri, - - [Parameter(ParameterSetName = 'PublishModule')] - [string[]] - $Exclude - ) - - Write-Verbose "Calling Publish-PSArtifactUtility" - Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -BootstrapNuGetExe - - $PSArtifactType = $script:PSArtifactTypeModule - $Name = $null - $Description = $null - $Version = "" - $Author = $null - $CompanyName = $null - $Copyright = $null - $requireLicenseAcceptance = "false" - - if ($PSModuleInfo) { - $Name = $PSModuleInfo.Name - $Description = $PSModuleInfo.Description - $Version = $PSModuleInfo.Version - $Author = $PSModuleInfo.Author - $CompanyName = $PSModuleInfo.CompanyName - $Copyright = $PSModuleInfo.Copyright - - if ($PSModuleInfo.PrivateData -and - ($PSModuleInfo.PrivateData.GetType().ToString() -eq "System.Collections.Hashtable") -and - $PSModuleInfo.PrivateData["PSData"] -and - ($PSModuleInfo.PrivateData["PSData"].GetType().ToString() -eq "System.Collections.Hashtable") - ) { - if ( -not $Tags -and $PSModuleInfo.PrivateData.PSData["Tags"]) { - $Tags = $PSModuleInfo.PrivateData.PSData.Tags - } - - if ( -not $ReleaseNotes -and $PSModuleInfo.PrivateData.PSData["ReleaseNotes"]) { - $ReleaseNotes = $PSModuleInfo.PrivateData.PSData.ReleaseNotes - } - - if ( -not $LicenseUri -and $PSModuleInfo.PrivateData.PSData["LicenseUri"]) { - $LicenseUri = $PSModuleInfo.PrivateData.PSData.LicenseUri - } - - if ( -not $IconUri -and $PSModuleInfo.PrivateData.PSData["IconUri"]) { - $IconUri = $PSModuleInfo.PrivateData.PSData.IconUri - } - - if ( -not $ProjectUri -and $PSModuleInfo.PrivateData.PSData["ProjectUri"]) { - $ProjectUri = $PSModuleInfo.PrivateData.PSData.ProjectUri - } - - if ($PSModuleInfo.PrivateData.PSData["Prerelease"]) { - $psmoduleInfoPrereleaseString = $PSModuleInfo.PrivateData.PSData.Prerelease - if ($psmoduleInfoPrereleaseString -and $psmoduleInfoPrereleaseString.StartsWith("-")) { - $Version = [string]$Version + $psmoduleInfoPrereleaseString - } - else { - $Version = [string]$Version + "-" + $psmoduleInfoPrereleaseString - } - } - - if ($PSModuleInfo.PrivateData.PSData["RequireLicenseAcceptance"]) { - $requireLicenseAcceptance = $PSModuleInfo.PrivateData.PSData.requireLicenseAcceptance.ToString().ToLower() - if ($requireLicenseAcceptance -eq "true") { - if ($FormatVersion -and ($FormatVersion.Major -lt $script:PSGetRequireLicenseAcceptanceFormatVersion.Major)) { - $message = $LocalizedData.requireLicenseAcceptanceNotSupported -f ($FormatVersion) - ThrowError -ExceptionName "System.InvalidOperationException" ` - -ExceptionMessage $message ` - -ErrorId "requireLicenseAcceptanceNotSupported" ` - -CallerPSCmdlet $PSCmdlet ` - -ErrorCategory InvalidData - } - - if (-not $LicenseUri) { - $message = $LocalizedData.LicenseUriNotSpecified - ThrowError -ExceptionName "System.InvalidOperationException" ` - -ExceptionMessage $message ` - -ErrorId "LicenseUriNotSpecified" ` - -CallerPSCmdlet $PSCmdlet ` - -ErrorCategory InvalidData - } - - $LicenseFilePath = Join-PathUtility -Path $NugetPackageRoot -ChildPath 'License.txt' -PathType File - if (-not $LicenseFilePath -or -not (Test-Path -Path $LicenseFilePath -PathType Leaf)) { - $message = $LocalizedData.LicenseTxtNotFound - ThrowError -ExceptionName "System.InvalidOperationException" ` - -ExceptionMessage $message ` - -ErrorId "LicenseTxtNotFound" ` - -CallerPSCmdlet $PSCmdlet ` - -ErrorCategory InvalidData - } - - if ((Get-Content -LiteralPath $LicenseFilePath) -eq $null) { - $message = $LocalizedData.LicenseTxtEmpty - ThrowError -ExceptionName "System.InvalidOperationException" ` - -ExceptionMessage $message ` - -ErrorId "LicenseTxtEmpty" ` - -CallerPSCmdlet $PSCmdlet ` - -ErrorCategory InvalidData - } - - #RequireLicenseAcceptance is true, License uri and license.txt exist. Bump Up the FormatVersion - if (-not $FormatVersion) { - $FormatVersion = $script:CurrentPSGetFormatVersion - } - } - elseif ($requireLicenseAcceptance -ne "false") { - $InvalidValueForRequireLicenseAcceptance = $LocalizedData.InvalidValueBoolean -f ($requireLicenseAcceptance, "requireLicenseAcceptance") - Write-Warning -Message $InvalidValueForRequireLicenseAcceptance - } - } - } - } - else { - $PSArtifactType = $script:PSArtifactTypeScript - - $Name = $PSScriptInfo.Name - $Description = $PSScriptInfo.Description - $Version = $PSScriptInfo.Version - $Author = $PSScriptInfo.Author - $CompanyName = $PSScriptInfo.CompanyName - $Copyright = $PSScriptInfo.Copyright - - if ($PSScriptInfo.'Tags') { - $Tags = $PSScriptInfo.Tags - } - - if ($PSScriptInfo.'ReleaseNotes') { - $ReleaseNotes = $PSScriptInfo.ReleaseNotes - } - - if ($PSScriptInfo.'LicenseUri') { - $LicenseUri = $PSScriptInfo.LicenseUri - } - - if ($PSScriptInfo.'IconUri') { - $IconUri = $PSScriptInfo.IconUri - } - - if ($PSScriptInfo.'ProjectUri') { - $ProjectUri = $PSScriptInfo.ProjectUri - } - } - - $nuspecFiles = "" - if ($Exclude) { - $nuspecFileExcludePattern = $Exclude -Join ";" - $nuspecFiles = @{ src = "**/*.*"; exclude = $nuspecFileExcludePattern } - } - - # Add PSModule and PSGet format version tags - if (-not $Tags) { - $Tags = @() - } - - if ($FormatVersion) { - $Tags += "$($script:PSGetFormatVersion)_$FormatVersion" - } - - $DependentModuleDetails = @() - - if ($PSScriptInfo) { - $Tags += "PSScript" - - if ($PSScriptInfo.DefinedCommands -and -not $SkipAutomaticTags) { - if ($PSScriptInfo.DefinedFunctions) { - $Tags += "$($script:Includes)_Function" - $Tags += $PSScriptInfo.DefinedFunctions | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Function)_$_" } - } - - if ($PSScriptInfo.DefinedWorkflows) { - $Tags += "$($script:Includes)_Workflow" - $Tags += $PSScriptInfo.DefinedWorkflows | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Workflow)_$_" } - } - - $Tags += $PSScriptInfo.DefinedCommands | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Command)_$_" } - } - - # Populate the dependencies elements from RequiredModules and RequiredScripts - # - $ValidateAndGetScriptDependencies_Params = @{ - Repository = $Repository - DependentScriptInfo = $PSScriptInfo - CallerPSCmdlet = $PSCmdlet - Verbose = $VerbosePreference - Debug = $DebugPreference - } - if ($PSBoundParameters.ContainsKey('Credential')) { - $ValidateAndGetScriptDependencies_Params.Add('Credential', $Credential) - } - $DependentModuleDetails += ValidateAndGet-ScriptDependencies @ValidateAndGetScriptDependencies_Params - } - else { - $Tags += "PSModule" - - $ModuleManifestHashTable = Get-ManifestHashTable -Path $ManifestPath - - if (-not $SkipAutomaticTags) { - if ($PSModuleInfo.ExportedCommands.Count) { - if ($PSModuleInfo.ExportedCmdlets.Count) { - $Tags += "$($script:Includes)_Cmdlet" - $Tags += $PSModuleInfo.ExportedCmdlets.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Cmdlet)_$_" } - - #if CmdletsToExport field in manifest file is "*", we suggest the user to include all those cmdlets for best practice - if ($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey('CmdletsToExport') -and ($ModuleManifestHashTable.CmdletsToExport -eq "*")) { - $WarningMessage = $LocalizedData.ShouldIncludeCmdletsToExport -f ($ManifestPath) - Write-Warning -Message $WarningMessage - } - } - - if ($PSModuleInfo.ExportedFunctions.Count) { - $Tags += "$($script:Includes)_Function" - $Tags += $PSModuleInfo.ExportedFunctions.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Function)_$_" } - - if ($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey('FunctionsToExport') -and ($ModuleManifestHashTable.FunctionsToExport -eq "*")) { - $WarningMessage = $LocalizedData.ShouldIncludeFunctionsToExport -f ($ManifestPath) - Write-Warning -Message $WarningMessage - } - } - - $Tags += $PSModuleInfo.ExportedCommands.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Command)_$_" } - } - - $dscResourceNames = Get-ExportedDscResources -PSModuleInfo $PSModuleInfo - if ($dscResourceNames) { - $Tags += "$($script:Includes)_DscResource" - - $Tags += $dscResourceNames | Microsoft.PowerShell.Core\ForEach-Object { "$($script:DscResource)_$_" } - - #If DscResourcesToExport is commented out or "*" is used, we will write-warning - if ($ModuleManifestHashTable -and - ($ModuleManifestHashTable.ContainsKey("DscResourcesToExport") -and - $ModuleManifestHashTable.DscResourcesToExport -eq "*") -or - -not $ModuleManifestHashTable.ContainsKey("DscResourcesToExport")) { - $WarningMessage = $LocalizedData.ShouldIncludeDscResourcesToExport -f ($ManifestPath) - Write-Warning -Message $WarningMessage - } - } - - $RoleCapabilityNames = Get-AvailableRoleCapabilityName -PSModuleInfo $PSModuleInfo - if ($RoleCapabilityNames) { - $Tags += "$($script:Includes)_RoleCapability" - - $Tags += $RoleCapabilityNames | Microsoft.PowerShell.Core\ForEach-Object { "$($script:RoleCapability)_$_" } - } - } - - # Populate the module dependencies elements from RequiredModules and - # NestedModules properties of the current PSModuleInfo - $GetModuleDependencies_Params = @{ - PSModuleInfo = $PSModuleInfo - Repository = $Repository - CallerPSCmdlet = $PSCmdlet - Verbose = $VerbosePreference - Debug = $DebugPreference - } - if ($PSBoundParameters.ContainsKey('Credential')) { - $GetModuleDependencies_Params.Add('Credential', $Credential) - } - $DependentModuleDetails = Get-ModuleDependencies @GetModuleDependencies_Params - } - - $dependencies = @() - ForEach ($Dependency in $DependentModuleDetails) { - $ModuleName = $Dependency.Name - $VersionString = "" - - # Version format in NuSpec: - # "[2.0]" --> (== 2.0) Required Version - # "2.0" --> (>= 2.0) Minimum Version - # - # When only MaximumVersion is specified in the ModuleSpecification - # (,1.0] = x <= 1.0 - # - # When both Minimum and Maximum versions are specified in the ModuleSpecification - # [1.0,2.0] = 1.0 <= x <= 2.0 - - if ($Dependency.Keys -Contains "RequiredVersion") { - $VersionString = "[$($Dependency.RequiredVersion)]" - } - elseif ($Dependency.Keys -Contains 'MinimumVersion' -and $Dependency.Keys -Contains 'MaximumVersion') { - $VersionString = "[$($Dependency.MinimumVersion),$($Dependency.MaximumVersion)]" - } - elseif ($Dependency.Keys -Contains 'MaximumVersion') { - $VersionString = "(,$($Dependency.MaximumVersion)]" - } - elseif ($Dependency.Keys -Contains 'MinimumVersion') { - $VersionString = "$($Dependency.MinimumVersion)" - } - - $props = @{ - id = $ModuleName - version = $VersionString - } - - $dependencyObject = New-Object -TypeName PSCustomObject -Property $props - $dependencies += $dependencyObject - } - - $params = @{ - OutputPath = $NugetPackageRoot - Id = $Name - Version = $Version - Authors = $Author - Owners = $CompanyName - Description = $Description - ReleaseNotes = $ReleaseNotes - RequireLicenseAcceptance = ($requireLicenseAcceptance -eq $true) - Copyright = $Copyright - Tags = $Tags - LicenseUrl = $LicenseUri - ProjectUrl = $ProjectUri - IconUrl = $IconUri - Dependencies = $dependencies - } - - if ($nuspecFiles) { - $params.Add('Files', $nuspecFiles) - } - - try { - $NuspecFullName = New-NuspecFile @params - } - catch { - Write-Error -Message "Failed to create nuspec file $_.Exception" -ErrorAction Stop - } - - try { - if ($DotnetCommandPath) { - $NupkgFullName = New-NugetPackage -NuspecPath $NuspecFullName -NugetPackageRoot $NugetPackageRoot -UseDotnetCli -Verbose:$VerbosePreference - } - elseif ($NuGetExePath) { - $NupkgFullName = New-NugetPackage -NuspecPath $NuspecFullName -NugetPackageRoot $NugetPackageRoot -NugetExePath $NuGetExePath -Verbose:$VerbosePreference - } - - Write-Verbose -Message "Successfully created nuget package at $NupkgFullName" - } - catch { - if ($PSArtifactType -eq $script:PSArtifactTypeModule) { - $message = $LocalizedData.FailedToCreateCompressedModule -f ($_.Exception.message) - $errorId = "FailedToCreateCompressedModule" - } - else { - $message = $LocalizedData.FailedToCreateCompressedScript -f ($_.Exception.message) - $errorId = "FailedToCreateCompressedScript" - } - - Write-Error -Message $message -ErrorId $errorId -Category InvalidOperation -ErrorAction Stop - } - - try { - if ($DotnetCommandPath) { - Publish-NugetPackage -NupkgPath $NupkgFullName -Destination $Destination -NugetApiKey $NugetApiKey -UseDotnetCli -Verbose:$VerbosePreference - } - if ($NuGetExePath) { - Publish-NugetPackage -NupkgPath $NupkgFullName -Destination $Destination -NugetApiKey $NugetApiKey -NugetExePath $NuGetExePath -Verbose:$VerbosePreference - } - - if ($PSArtifactType -eq "Module") { - $message = $LocalizedData.PublishedSuccessfully -f ($Name, $Destination, $Name) - } - if ($PSArtifactType -eq "Script") { - $message = $LocalizedData.PublishedScriptSuccessfully -f ($Name, $Destination, $Name) - } - - Write-Verbose -Message $message - } - catch { - if ( $NugetApiKey -eq "VSTS" -and ($_.Exception.Message -match "Cannot prompt for input in non-interactive mode.")) { - $message = $LocalizedData.RegisterVSTSFeedAsNuGetPackageSource -f ($Destination, $script:VSTSAuthenticatedFeedsDocUrl) - } - else { - $message = $_.Exception.message - } - - if ($PSArtifactType -eq "Module") { - $errorMessage = $LocalizedData.FailedToPublish -f ($Name, $message) - $errorId = "FailedToPublishTheModule" - } - - if ($PSArtifactType -eq "Script") { - $errorMessage = $LocalizedData.FailedToPublishScript -f ($Name, $message) - $errorId = "FailedToPublishTheScript" - } - - Write-Error -Message $errorMessage -ErrorId $errorId -Category InvalidOperation -ErrorAction Stop - } -} + [CmdletBinding(PositionalBinding = $false)] + Param + ( + [Parameter(Mandatory = $true, ParameterSetName = 'PublishModule')] + [ValidateNotNullOrEmpty()] + [PSModuleInfo] + $PSModuleInfo, + + [Parameter(Mandatory = $true, ParameterSetName = 'PublishScript')] + [ValidateNotNullOrEmpty()] + [PSCustomObject] + $PSScriptInfo, + + [Parameter(Mandatory = $true, ParameterSetName = 'PublishModule')] + [ValidateNotNullOrEmpty()] + [string] + $ManifestPath, + + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string] + $Destination, + + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string] + $Repository, + + [Parameter(Mandatory = $false)] + [string] + $NugetApiKey, + + [Parameter(Mandatory = $false)] + [pscredential] + $Credential, + + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string] + $NugetPackageRoot, + + [Parameter(ParameterSetName = 'PublishModule')] + [Version] + $FormatVersion, + + [Parameter(ParameterSetName = 'PublishModule')] + [string] + $ReleaseNotes, + + [Parameter(ParameterSetName = 'PublishModule')] + [string[]] + $Tags, + + [Parameter(ParameterSetName = 'PublishModule')] + [switch] + $SkipAutomaticTags, + + [Parameter(ParameterSetName = 'PublishModule')] + [Uri] + $LicenseUri, + + [Parameter(ParameterSetName = 'PublishModule')] + [Uri] + $IconUri, + + [Parameter(ParameterSetName = 'PublishModule')] + [Uri] + $ProjectUri, + + [Parameter(ParameterSetName = 'PublishModule')] + [string[]] + $Exclude + ) + + Write-Verbose "Calling Publish-PSArtifactUtility" + Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -BootstrapNuGetExe + + $PSArtifactType = $script:PSArtifactTypeModule + $Name = $null + $Description = $null + $Version = "" + $Author = $null + $CompanyName = $null + $Copyright = $null + $requireLicenseAcceptance = "false" + + if ($PSModuleInfo) { + $Name = $PSModuleInfo.Name + $Description = $PSModuleInfo.Description + $Version = $PSModuleInfo.Version + $Author = $PSModuleInfo.Author + $CompanyName = $PSModuleInfo.CompanyName + $Copyright = $PSModuleInfo.Copyright + + if ($PSModuleInfo.PrivateData -and + ($PSModuleInfo.PrivateData.GetType().ToString() -eq "System.Collections.Hashtable") -and + $PSModuleInfo.PrivateData["PSData"] -and + ($PSModuleInfo.PrivateData["PSData"].GetType().ToString() -eq "System.Collections.Hashtable") + ) { + if ( -not $Tags -and $PSModuleInfo.PrivateData.PSData["Tags"]) { + $Tags = $PSModuleInfo.PrivateData.PSData.Tags + } + + if ( -not $ReleaseNotes -and $PSModuleInfo.PrivateData.PSData["ReleaseNotes"]) { + $ReleaseNotes = $PSModuleInfo.PrivateData.PSData.ReleaseNotes + } + + if ( -not $LicenseUri -and $PSModuleInfo.PrivateData.PSData["LicenseUri"]) { + $LicenseUri = $PSModuleInfo.PrivateData.PSData.LicenseUri + } + + if ( -not $IconUri -and $PSModuleInfo.PrivateData.PSData["IconUri"]) { + $IconUri = $PSModuleInfo.PrivateData.PSData.IconUri + } + + if ( -not $ProjectUri -and $PSModuleInfo.PrivateData.PSData["ProjectUri"]) { + $ProjectUri = $PSModuleInfo.PrivateData.PSData.ProjectUri + } + + if ($PSModuleInfo.PrivateData.PSData["Prerelease"]) { + $psmoduleInfoPrereleaseString = $PSModuleInfo.PrivateData.PSData.Prerelease + if ($psmoduleInfoPrereleaseString -and $psmoduleInfoPrereleaseString.StartsWith("-")) { + $Version = [string]$Version + $psmoduleInfoPrereleaseString + } + else { + $Version = [string]$Version + "-" + $psmoduleInfoPrereleaseString + } + } + + if ($PSModuleInfo.PrivateData.PSData["RequireLicenseAcceptance"]) { + $requireLicenseAcceptance = $PSModuleInfo.PrivateData.PSData.requireLicenseAcceptance.ToString().ToLower() + if ($requireLicenseAcceptance -eq "true") { + if ($FormatVersion -and ($FormatVersion.Major -lt $script:PSGetRequireLicenseAcceptanceFormatVersion.Major)) { + $message = $LocalizedData.requireLicenseAcceptanceNotSupported -f ($FormatVersion) + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "requireLicenseAcceptanceNotSupported" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidData + } + + if (-not $LicenseUri) { + $message = $LocalizedData.LicenseUriNotSpecified + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "LicenseUriNotSpecified" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidData + } + + $LicenseFilePath = Join-PathUtility -Path $NugetPackageRoot -ChildPath 'License.txt' -PathType File + if (-not $LicenseFilePath -or -not (Test-Path -Path $LicenseFilePath -PathType Leaf)) { + $message = $LocalizedData.LicenseTxtNotFound + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "LicenseTxtNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidData + } + + if ((Get-Content -LiteralPath $LicenseFilePath) -eq $null) { + $message = $LocalizedData.LicenseTxtEmpty + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "LicenseTxtEmpty" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidData + } + + #RequireLicenseAcceptance is true, License uri and license.txt exist. Bump Up the FormatVersion + if (-not $FormatVersion) { + $FormatVersion = $script:CurrentPSGetFormatVersion + } + } + elseif ($requireLicenseAcceptance -ne "false") { + $InvalidValueForRequireLicenseAcceptance = $LocalizedData.InvalidValueBoolean -f ($requireLicenseAcceptance, "requireLicenseAcceptance") + Write-Warning -Message $InvalidValueForRequireLicenseAcceptance + } + } + } + } + else { + $PSArtifactType = $script:PSArtifactTypeScript + + $Name = $PSScriptInfo.Name + $Description = $PSScriptInfo.Description + $Version = $PSScriptInfo.Version + $Author = $PSScriptInfo.Author + $CompanyName = $PSScriptInfo.CompanyName + $Copyright = $PSScriptInfo.Copyright + + if ($PSScriptInfo.'Tags') { + $Tags = $PSScriptInfo.Tags + } + + if ($PSScriptInfo.'ReleaseNotes') { + $ReleaseNotes = $PSScriptInfo.ReleaseNotes + } + + if ($PSScriptInfo.'LicenseUri') { + $LicenseUri = $PSScriptInfo.LicenseUri + } + + if ($PSScriptInfo.'IconUri') { + $IconUri = $PSScriptInfo.IconUri + } + + if ($PSScriptInfo.'ProjectUri') { + $ProjectUri = $PSScriptInfo.ProjectUri + } + } + + $nuspecFiles = "" + if ($Exclude) { + $nuspecFileExcludePattern = $Exclude -Join ";" + $nuspecFiles = @{ src = "**/*.*"; exclude = $nuspecFileExcludePattern } + } + + # Add PSModule and PSGet format version tags + if (-not $Tags) { + $Tags = @() + } + + if ($FormatVersion) { + $Tags += "$($script:PSGetFormatVersion)_$FormatVersion" + } + + $DependentModuleDetails = @() + + if ($PSScriptInfo) { + $Tags += "PSScript" + + if ($PSScriptInfo.DefinedCommands -and -not $SkipAutomaticTags) { + if ($PSScriptInfo.DefinedFunctions) { + $Tags += "$($script:Includes)_Function" + $Tags += $PSScriptInfo.DefinedFunctions | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Function)_$_" } + } + + if ($PSScriptInfo.DefinedWorkflows) { + $Tags += "$($script:Includes)_Workflow" + $Tags += $PSScriptInfo.DefinedWorkflows | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Workflow)_$_" } + } + + $Tags += $PSScriptInfo.DefinedCommands | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Command)_$_" } + } + + # Populate the dependencies elements from RequiredModules and RequiredScripts + # + $ValidateAndGetScriptDependencies_Params = @{ + Repository = $Repository + DependentScriptInfo = $PSScriptInfo + CallerPSCmdlet = $PSCmdlet + Verbose = $VerbosePreference + Debug = $DebugPreference + } + if ($PSBoundParameters.ContainsKey('Credential')) { + $ValidateAndGetScriptDependencies_Params.Add('Credential', $Credential) + } + $DependentModuleDetails += ValidateAndGet-ScriptDependencies @ValidateAndGetScriptDependencies_Params + } + else { + $Tags += "PSModule" + + $ModuleManifestHashTable = Get-ManifestHashTable -Path $ManifestPath + + if (-not $SkipAutomaticTags) { + if ($PSModuleInfo.ExportedCommands.Count) { + if ($PSModuleInfo.ExportedCmdlets.Count) { + $Tags += "$($script:Includes)_Cmdlet" + $Tags += $PSModuleInfo.ExportedCmdlets.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Cmdlet)_$_" } + + #if CmdletsToExport field in manifest file is "*", we suggest the user to include all those cmdlets for best practice + if ($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey('CmdletsToExport') -and ($ModuleManifestHashTable.CmdletsToExport -eq "*")) { + $WarningMessage = $LocalizedData.ShouldIncludeCmdletsToExport -f ($ManifestPath) + Write-Warning -Message $WarningMessage + } + } + + if ($PSModuleInfo.ExportedFunctions.Count) { + $Tags += "$($script:Includes)_Function" + $Tags += $PSModuleInfo.ExportedFunctions.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Function)_$_" } + + if ($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey('FunctionsToExport') -and ($ModuleManifestHashTable.FunctionsToExport -eq "*")) { + $WarningMessage = $LocalizedData.ShouldIncludeFunctionsToExport -f ($ManifestPath) + Write-Warning -Message $WarningMessage + } + } + + $Tags += $PSModuleInfo.ExportedCommands.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Command)_$_" } + } + + $dscResourceNames = Get-ExportedDscResources -PSModuleInfo $PSModuleInfo + if ($dscResourceNames) { + $Tags += "$($script:Includes)_DscResource" + + $Tags += $dscResourceNames | Microsoft.PowerShell.Core\ForEach-Object { "$($script:DscResource)_$_" } + + #If DscResourcesToExport is commented out or "*" is used, we will write-warning + if ($ModuleManifestHashTable -and + ($ModuleManifestHashTable.ContainsKey("DscResourcesToExport") -and + $ModuleManifestHashTable.DscResourcesToExport -eq "*") -or + -not $ModuleManifestHashTable.ContainsKey("DscResourcesToExport")) { + $WarningMessage = $LocalizedData.ShouldIncludeDscResourcesToExport -f ($ManifestPath) + Write-Warning -Message $WarningMessage + } + } + + $RoleCapabilityNames = Get-AvailableRoleCapabilityName -PSModuleInfo $PSModuleInfo + if ($RoleCapabilityNames) { + $Tags += "$($script:Includes)_RoleCapability" + + $Tags += $RoleCapabilityNames | Microsoft.PowerShell.Core\ForEach-Object { "$($script:RoleCapability)_$_" } + } + } + + # Populate the module dependencies elements from RequiredModules and + # NestedModules properties of the current PSModuleInfo + $GetModuleDependencies_Params = @{ + PSModuleInfo = $PSModuleInfo + Repository = $Repository + CallerPSCmdlet = $PSCmdlet + Verbose = $VerbosePreference + Debug = $DebugPreference + } + if ($PSBoundParameters.ContainsKey('Credential')) { + $GetModuleDependencies_Params.Add('Credential', $Credential) + } + $DependentModuleDetails = Get-ModuleDependencies @GetModuleDependencies_Params + } + + $dependencies = @() + ForEach ($Dependency in $DependentModuleDetails) { + $ModuleName = $Dependency.Name + $VersionString = "" + + # Version format in NuSpec: + # "[2.0]" --> (== 2.0) Required Version + # "2.0" --> (>= 2.0) Minimum Version + # + # When only MaximumVersion is specified in the ModuleSpecification + # (,1.0] = x <= 1.0 + # + # When both Minimum and Maximum versions are specified in the ModuleSpecification + # [1.0,2.0] = 1.0 <= x <= 2.0 + + if ($Dependency.Keys -Contains "RequiredVersion") { + $VersionString = "[$($Dependency.RequiredVersion)]" + } + elseif ($Dependency.Keys -Contains 'MinimumVersion' -and $Dependency.Keys -Contains 'MaximumVersion') { + $VersionString = "[$($Dependency.MinimumVersion),$($Dependency.MaximumVersion)]" + } + elseif ($Dependency.Keys -Contains 'MaximumVersion') { + $VersionString = "(,$($Dependency.MaximumVersion)]" + } + elseif ($Dependency.Keys -Contains 'MinimumVersion') { + $VersionString = "$($Dependency.MinimumVersion)" + } + + $props = @{ + id = $ModuleName + version = $VersionString + } + + $dependencyObject = New-Object -TypeName PSCustomObject -Property $props + $dependencies += $dependencyObject + } + + $params = @{ + OutputPath = $NugetPackageRoot + Id = $Name + Version = $Version + Authors = $Author + Owners = $CompanyName + Description = $Description + ReleaseNotes = $ReleaseNotes + RequireLicenseAcceptance = ($requireLicenseAcceptance -eq $true) + Copyright = $Copyright + Tags = $Tags + LicenseUrl = $LicenseUri + ProjectUrl = $ProjectUri + IconUrl = $IconUri + Dependencies = $dependencies + } + + if ($nuspecFiles) { + $params.Add('Files', $nuspecFiles) + } + + try { + $NuspecFullName = New-NuspecFile @params + } + catch { + Write-Error -Message "Failed to create nuspec file $_.Exception" -ErrorAction Stop + } + + try { + if ($DotnetCommandPath) { + $NupkgFullName = New-NugetPackage -NuspecPath $NuspecFullName -NugetPackageRoot $NugetPackageRoot -UseDotnetCli -Verbose:$VerbosePreference + } + elseif ($NuGetExePath) { + $NupkgFullName = New-NugetPackage -NuspecPath $NuspecFullName -NugetPackageRoot $NugetPackageRoot -NugetExePath $NuGetExePath -Verbose:$VerbosePreference + } + + <<<<<<< HEAD + Write-Verbose -Message "Successfully created nuget package at $NupkgFullName" + } + catch { + if ($PSArtifactType -eq $script:PSArtifactTypeModule) { + $message = $LocalizedData.FailedToCreateCompressedModule -f ($_.Exception.message) + $errorId = "FailedToCreateCompressedModule" + ======= + if ($script:DotnetCommandPath) { + $StartProcess_params['FilePath'] = $script:DotnetCommandPath + + $ArgumentList = @('nuget') + $ArgumentList += 'push' + $ArgumentList += "`"$NupkgPath`"" + $ArgumentList += @('--source', "`"$($Destination.TrimEnd('\'))`"") + + if ($PSBoundParameters.Containskey('NugetApiKey')) { + $ArgumentList += @('--api-key', "`"$NugetApiKey`"") + } + } + elseif ($script:NuGetExePath) { + $StartProcess_params['FilePath'] = $script:NuGetExePath + + $ArgumentList = @('push') + $ArgumentList += "`"$NupkgPath`"" + $ArgumentList += @('-source', "`"$($Destination.TrimEnd('\'))`"") + $ArgumentList += '-NonInteractive' + if ($PSBoundParameters.Containskey('NugetApiKey')) { + $ArgumentList += @('--api-key', "`"$NugetApiKey`"") + } + >>>>>>> Remove validation on NugetApiKey parameter + } + else { + $message = $LocalizedData.FailedToCreateCompressedScript -f ($_.Exception.message) + $errorId = "FailedToCreateCompressedScript" + } + + Write-Error -Message $message -ErrorId $errorId -Category InvalidOperation -ErrorAction Stop + } + + try { + if ($DotnetCommandPath) { + Publish-NugetPackage -NupkgPath $NupkgFullName -Destination $Destination -NugetApiKey $NugetApiKey -UseDotnetCli -Verbose:$VerbosePreference + } + if ($NuGetExePath) { + Publish-NugetPackage -NupkgPath $NupkgFullName -Destination $Destination -NugetApiKey $NugetApiKey -NugetExePath $NuGetExePath -Verbose:$VerbosePreference + } + + if ($PSArtifactType -eq "Module") { + $message = $LocalizedData.PublishedSuccessfully -f ($Name, $Destination, $Name) + } + if ($PSArtifactType -eq "Script") { + $message = $LocalizedData.PublishedScriptSuccessfully -f ($Name, $Destination, $Name) + } + + Write-Verbose -Message $message + } + catch { + if ( $NugetApiKey -eq "VSTS" -and ($_.Exception.Message -match "Cannot prompt for input in non-interactive mode.")) { + $message = $LocalizedData.RegisterVSTSFeedAsNuGetPackageSource -f ($Destination, $script:VSTSAuthenticatedFeedsDocUrl) + } + else { + $message = $_.Exception.message + } + + if ($PSArtifactType -eq "Module") { + $errorMessage = $LocalizedData.FailedToPublish -f ($Name, $message) + $errorId = "FailedToPublishTheModule" + } + + if ($PSArtifactType -eq "Script") { + $errorMessage = $LocalizedData.FailedToPublishScript -f ($Name, $message) + $errorId = "FailedToPublishTheScript" + } + + Write-Error -Message $errorMessage -ErrorId $errorId -Category InvalidOperation -ErrorAction Stop + } + } diff --git a/src/PowerShellGet/public/psgetfunctions/Publish-Module.ps1 b/src/PowerShellGet/public/psgetfunctions/Publish-Module.ps1 index f0fd6776..322dddee 100644 --- a/src/PowerShellGet/public/psgetfunctions/Publish-Module.ps1 +++ b/src/PowerShellGet/public/psgetfunctions/Publish-Module.ps1 @@ -28,7 +28,6 @@ function Publish-Module { $RequiredVersion, [Parameter()] - [ValidateNotNullOrEmpty()] [string] $NuGetApiKey, @@ -159,20 +158,6 @@ function Publish-Module { $message = $LocalizedData.PublishLocation -f ($DestinationLocation) Write-Verbose -Message $message - if (-not $NuGetApiKey.Trim()) { - if (Microsoft.PowerShell.Management\Test-Path -Path $DestinationLocation) { - $NuGetApiKey = "$(Get-Random)" - } - else { - $message = $LocalizedData.NuGetApiKeyIsRequiredForNuGetBasedGalleryService -f ($Repository, $DestinationLocation) - ThrowError -ExceptionName "System.ArgumentException" ` - -ExceptionMessage $message ` - -ErrorId "NuGetApiKeyIsRequiredForNuGetBasedGalleryService" ` - -CallerPSCmdlet $PSCmdlet ` - -ErrorCategory InvalidArgument - } - } - $providerName = Get-ProviderName -PSCustomObject $moduleSource if ($providerName -ne $script:NuGetProviderName) { $message = $LocalizedData.PublishModuleSupportsOnlyNuGetBasedPublishLocations -f ($moduleSource.PublishLocation, $Repository, $Repository) @@ -549,6 +534,7 @@ function Publish-Module { $shouldProcessMessage = $LocalizedData.PublishModulewhatIfMessage -f ($moduleInfo.Version, $moduleInfo.Name) if ($Force -or $PSCmdlet.ShouldProcess($shouldProcessMessage, "Publish-Module")) { $PublishPSArtifactUtility_Params = @{ +<<<<<<< HEAD PSModuleInfo = $moduleInfo ManifestPath = $manifestPath NugetApiKey = $NuGetApiKey @@ -566,12 +552,34 @@ function Publish-Module { WarningAction = $WarningPreference ErrorAction = $ErrorActionPreference Debug = $DebugPreference +======= + PSModuleInfo = $moduleInfo + ManifestPath = $manifestPath + Destination = $DestinationLocation + Repository = $Repository + NugetPackageRoot = $tempModulePath + FormatVersion = $FormatVersion + ReleaseNotes = $($ReleaseNotes -join "`r`n") + Tags = $Tags + LicenseUri = $LicenseUri + IconUri = $IconUri + ProjectUri = $ProjectUri + Verbose = $VerbosePreference + WarningAction = $WarningPreference + ErrorAction = $ErrorActionPreference + Debug = $DebugPreference +>>>>>>> Remove validation on NugetApiKey parameter } if ($PSBoundParameters.Containskey('Credential')) { $PublishPSArtifactUtility_Params.Add('Credential', $Credential) } +<<<<<<< HEAD if ($Exclude) { $PublishPSArtifactUtility_Params.Add('Exclude', $Exclude) +======= + if ($PSBoundParameters.Containskey('NugetApiKey')) { + $PublishPSArtifactUtility_Params.Add('NugetApiKey', $NuGetApiKey) +>>>>>>> Remove validation on NugetApiKey parameter } Publish-PSArtifactUtility @PublishPSArtifactUtility_Params } From efe1de6bbc9c4555c589a14faca65184b36c251c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hei=C3=B0ar=20H=C3=B3lmberg=20J=C3=B3nsson?= Date: Tue, 21 May 2019 09:37:43 +0000 Subject: [PATCH 18/19] Catch nuget error and diplay localized error instead --- .../functions/Publish-PSArtifactUtility.ps1 | 650 ++++++++++++++++++ 1 file changed, 650 insertions(+) diff --git a/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 b/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 index 009cd5ff..7834d3bf 100644 --- a/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 +++ b/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 @@ -1,3 +1,4 @@ +<<<<<<< HEAD function Publish-PSArtifactUtility { [CmdletBinding(PositionalBinding = $false)] Param @@ -480,3 +481,652 @@ function Publish-PSArtifactUtility { Write-Error -Message $errorMessage -ErrorId $errorId -Category InvalidOperation -ErrorAction Stop } } +======= +function Publish-PSArtifactUtility +{ + [CmdletBinding(PositionalBinding=$false)] + Param + ( + [Parameter(Mandatory=$true, ParameterSetName='PublishModule')] + [ValidateNotNullOrEmpty()] + [PSModuleInfo] + $PSModuleInfo, + + [Parameter(Mandatory=$true, ParameterSetName='PublishScript')] + [ValidateNotNullOrEmpty()] + [PSCustomObject] + $PSScriptInfo, + + [Parameter(Mandatory=$true, ParameterSetName='PublishModule')] + [ValidateNotNullOrEmpty()] + [string] + $ManifestPath, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Destination, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Repository, + + [Parameter(Mandatory=$false)] + [string] + $NugetApiKey, + + [Parameter(Mandatory=$false)] + [pscredential] + $Credential, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $NugetPackageRoot, + + [Parameter(ParameterSetName='PublishModule')] + [Version] + $FormatVersion, + + [Parameter(ParameterSetName='PublishModule')] + [string] + $ReleaseNotes, + + [Parameter(ParameterSetName='PublishModule')] + [string[]] + $Tags, + + [Parameter(ParameterSetName='PublishModule')] + [Uri] + $LicenseUri, + + [Parameter(ParameterSetName='PublishModule')] + [Uri] + $IconUri, + + [Parameter(ParameterSetName='PublishModule')] + [Uri] + $ProjectUri + ) + + Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -BootstrapNuGetExe + + $PSArtifactType = $script:PSArtifactTypeModule + $Name = $null + $Description = $null + $Version = "" + $Author = $null + $CompanyName = $null + $Copyright = $null + $requireLicenseAcceptance = "false" + + if($PSModuleInfo) + { + $Name = $PSModuleInfo.Name + $Description = $PSModuleInfo.Description + $Version = $PSModuleInfo.Version + $Author = $PSModuleInfo.Author + $CompanyName = $PSModuleInfo.CompanyName + $Copyright = $PSModuleInfo.Copyright + + if($PSModuleInfo.PrivateData -and + ($PSModuleInfo.PrivateData.GetType().ToString() -eq "System.Collections.Hashtable") -and + $PSModuleInfo.PrivateData["PSData"] -and + ($PSModuleInfo.PrivateData["PSData"].GetType().ToString() -eq "System.Collections.Hashtable") + ) + { + if( -not $Tags -and $PSModuleInfo.PrivateData.PSData["Tags"]) + { + $Tags = $PSModuleInfo.PrivateData.PSData.Tags + } + + if( -not $ReleaseNotes -and $PSModuleInfo.PrivateData.PSData["ReleaseNotes"]) + { + $ReleaseNotes = $PSModuleInfo.PrivateData.PSData.ReleaseNotes + } + + if( -not $LicenseUri -and $PSModuleInfo.PrivateData.PSData["LicenseUri"]) + { + $LicenseUri = $PSModuleInfo.PrivateData.PSData.LicenseUri + } + + if( -not $IconUri -and $PSModuleInfo.PrivateData.PSData["IconUri"]) + { + $IconUri = $PSModuleInfo.PrivateData.PSData.IconUri + } + + if( -not $ProjectUri -and $PSModuleInfo.PrivateData.PSData["ProjectUri"]) + { + $ProjectUri = $PSModuleInfo.PrivateData.PSData.ProjectUri + } + + if ($PSModuleInfo.PrivateData.PSData["Prerelease"]) + { + $psmoduleInfoPrereleaseString = $PSModuleInfo.PrivateData.PSData.Prerelease + if ($psmoduleInfoPrereleaseString -and $psmoduleInfoPrereleaseString.StartsWith("-")) + { + $Version = [string]$Version + $psmoduleInfoPrereleaseString + } + else + { + $Version = [string]$Version + "-" + $psmoduleInfoPrereleaseString + } + } + + if($PSModuleInfo.PrivateData.PSData["RequireLicenseAcceptance"]) + { + $requireLicenseAcceptance = $PSModuleInfo.PrivateData.PSData.requireLicenseAcceptance.ToString().ToLower() + if($requireLicenseAcceptance -eq "true") + { + if($FormatVersion -and ($FormatVersion.Major -lt $script:PSGetRequireLicenseAcceptanceFormatVersion.Major)) + { + $message = $LocalizedData.requireLicenseAcceptanceNotSupported -f($FormatVersion) + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "requireLicenseAcceptanceNotSupported" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidData + } + + if(-not $LicenseUri) + { + $message = $LocalizedData.LicenseUriNotSpecified + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "LicenseUriNotSpecified" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidData + } + + $LicenseFilePath = Join-PathUtility -Path $NugetPackageRoot -ChildPath 'License.txt' -PathType File + if(-not $LicenseFilePath -or -not (Test-Path -Path $LicenseFilePath -PathType Leaf)) + { + $message = $LocalizedData.LicenseTxtNotFound + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "LicenseTxtNotFound" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidData + } + + if((Get-Content -LiteralPath $LicenseFilePath) -eq $null) + { + $message = $LocalizedData.LicenseTxtEmpty + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage $message ` + -ErrorId "LicenseTxtEmpty" ` + -CallerPSCmdlet $PSCmdlet ` + -ErrorCategory InvalidData + } + + #RequireLicenseAcceptance is true, License uri and license.txt exist. Bump Up the FormatVersion + if(-not $FormatVersion) + { + $FormatVersion = $script:CurrentPSGetFormatVersion + } + } + elseif($requireLicenseAcceptance -ne "false") + { + $InvalidValueForRequireLicenseAcceptance = $LocalizedData.InvalidValueBoolean -f ($requireLicenseAcceptance, "requireLicenseAcceptance") + Write-Warning -Message $InvalidValueForRequireLicenseAcceptance + } + } + } + } + else + { + $PSArtifactType = $script:PSArtifactTypeScript + + $Name = $PSScriptInfo.Name + $Description = $PSScriptInfo.Description + $Version = $PSScriptInfo.Version + $Author = $PSScriptInfo.Author + $CompanyName = $PSScriptInfo.CompanyName + $Copyright = $PSScriptInfo.Copyright + + if($PSScriptInfo.'Tags') + { + $Tags = $PSScriptInfo.Tags + } + + if($PSScriptInfo.'ReleaseNotes') + { + $ReleaseNotes = $PSScriptInfo.ReleaseNotes + } + + if($PSScriptInfo.'LicenseUri') + { + $LicenseUri = $PSScriptInfo.LicenseUri + } + + if($PSScriptInfo.'IconUri') + { + $IconUri = $PSScriptInfo.IconUri + } + + if($PSScriptInfo.'ProjectUri') + { + $ProjectUri = $PSScriptInfo.ProjectUri + } + } + + + # Add PSModule and PSGet format version tags + if(-not $Tags) + { + $Tags = @() + } + + if($FormatVersion) + { + $Tags += "$($script:PSGetFormatVersion)_$FormatVersion" + } + + $DependentModuleDetails = @() + + if($PSScriptInfo) + { + $Tags += "PSScript" + + if($PSScriptInfo.DefinedCommands) + { + if($PSScriptInfo.DefinedFunctions) + { + $Tags += "$($script:Includes)_Function" + $Tags += $PSScriptInfo.DefinedFunctions | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Function)_$_" } + } + + if($PSScriptInfo.DefinedWorkflows) + { + $Tags += "$($script:Includes)_Workflow" + $Tags += $PSScriptInfo.DefinedWorkflows | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Workflow)_$_" } + } + + $Tags += $PSScriptInfo.DefinedCommands | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Command)_$_" } + } + + # Populate the dependencies elements from RequiredModules and RequiredScripts + # + $ValidateAndGetScriptDependencies_Params = @{ + Repository=$Repository + DependentScriptInfo=$PSScriptInfo + CallerPSCmdlet=$PSCmdlet + Verbose=$VerbosePreference + Debug=$DebugPreference + } + if ($PSBoundParameters.ContainsKey('Credential')) + { + $ValidateAndGetScriptDependencies_Params.Add('Credential',$Credential) + } + $DependentModuleDetails += ValidateAndGet-ScriptDependencies @ValidateAndGetScriptDependencies_Params + } + else + { + $Tags += "PSModule" + + $ModuleManifestHashTable = Get-ManifestHashTable -Path $ManifestPath + + if($PSModuleInfo.ExportedCommands.Count) + { + if($PSModuleInfo.ExportedCmdlets.Count) + { + $Tags += "$($script:Includes)_Cmdlet" + $Tags += $PSModuleInfo.ExportedCmdlets.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Cmdlet)_$_" } + + #if CmdletsToExport field in manifest file is "*", we suggest the user to include all those cmdlets for best practice + if($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey('CmdletsToExport') -and ($ModuleManifestHashTable.CmdletsToExport -eq "*")) + { + $WarningMessage = $LocalizedData.ShouldIncludeCmdletsToExport -f ($ManifestPath) + Write-Warning -Message $WarningMessage + } + } + + if($PSModuleInfo.ExportedFunctions.Count) + { + $Tags += "$($script:Includes)_Function" + $Tags += $PSModuleInfo.ExportedFunctions.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Function)_$_" } + + if($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey('FunctionsToExport') -and ($ModuleManifestHashTable.FunctionsToExport -eq "*")) + { + $WarningMessage = $LocalizedData.ShouldIncludeFunctionsToExport -f ($ManifestPath) + Write-Warning -Message $WarningMessage + } + } + + $Tags += $PSModuleInfo.ExportedCommands.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Command)_$_" } + } + + $dscResourceNames = Get-ExportedDscResources -PSModuleInfo $PSModuleInfo + if($dscResourceNames) + { + $Tags += "$($script:Includes)_DscResource" + + $Tags += $dscResourceNames | Microsoft.PowerShell.Core\ForEach-Object { "$($script:DscResource)_$_" } + + #If DscResourcesToExport is commented out or "*" is used, we will write-warning + if($ModuleManifestHashTable -and + ($ModuleManifestHashTable.ContainsKey("DscResourcesToExport") -and + $ModuleManifestHashTable.DscResourcesToExport -eq "*") -or + -not $ModuleManifestHashTable.ContainsKey("DscResourcesToExport")) + { + $WarningMessage = $LocalizedData.ShouldIncludeDscResourcesToExport -f ($ManifestPath) + Write-Warning -Message $WarningMessage + } + } + + $RoleCapabilityNames = Get-AvailableRoleCapabilityName -PSModuleInfo $PSModuleInfo + if($RoleCapabilityNames) + { + $Tags += "$($script:Includes)_RoleCapability" + + $Tags += $RoleCapabilityNames | Microsoft.PowerShell.Core\ForEach-Object { "$($script:RoleCapability)_$_" } + } + + # Populate the module dependencies elements from RequiredModules and + # NestedModules properties of the current PSModuleInfo + $GetModuleDependencies_Params = @{ + PSModuleInfo=$PSModuleInfo + Repository=$Repository + CallerPSCmdlet=$PSCmdlet + Verbose=$VerbosePreference + Debug=$DebugPreference + } + if ($PSBoundParameters.ContainsKey('Credential')) + { + $GetModuleDependencies_Params.Add('Credential',$Credential) + } + $DependentModuleDetails = Get-ModuleDependencies @GetModuleDependencies_Params + } + + $dependencies = @() + ForEach($Dependency in $DependentModuleDetails) + { + $ModuleName = $Dependency.Name + $VersionString = $null + + # Version format in NuSpec: + # "[2.0]" --> (== 2.0) Required Version + # "2.0" --> (>= 2.0) Minimum Version + # + # When only MaximumVersion is specified in the ModuleSpecification + # (,1.0] = x <= 1.0 + # + # When both Minimum and Maximum versions are specified in the ModuleSpecification + # [1.0,2.0] = 1.0 <= x <= 2.0 + + if($Dependency.Keys -Contains "RequiredVersion") + { + $VersionString = "[$($Dependency.RequiredVersion)]" + } + elseif($Dependency.Keys -Contains 'MinimumVersion' -and $Dependency.Keys -Contains 'MaximumVersion') + { + $VersionString = "[$($Dependency.MinimumVersion),$($Dependency.MaximumVersion)]" + } + elseif($Dependency.Keys -Contains 'MaximumVersion') + { + $VersionString = "(,$($Dependency.MaximumVersion)]" + } + elseif($Dependency.Keys -Contains 'MinimumVersion') + { + $VersionString = "$($Dependency.MinimumVersion)" + } + + if ([System.string]::IsNullOrWhiteSpace($VersionString)) + { + $dependencies += "" + } + else + { + $dependencies += "" + } + } + + # Populate the nuspec elements + $nuspec = @" + + + + $(Get-EscapedString -ElementValue "$Name") + $($Version) + $(Get-EscapedString -ElementValue "$Author") + $(Get-EscapedString -ElementValue "$CompanyName") + $(Get-EscapedString -ElementValue "$Description") + $(Get-EscapedString -ElementValue "$ReleaseNotes") + $($requireLicenseAcceptance.ToString()) + $(Get-EscapedString -ElementValue "$Copyright") + $(if($Tags){ Get-EscapedString -ElementValue ($Tags -join ' ')}) + $(if($LicenseUri){ + "$(Get-EscapedString -ElementValue "$LicenseUri")" + }) + $(if($ProjectUri){ + "$(Get-EscapedString -ElementValue "$ProjectUri")" + }) + $(if($IconUri){ + "$(Get-EscapedString -ElementValue "$IconUri")" + }) + + $dependencies + + + +"@ + +# When packaging we must build something. +# So, we are building an empty assembly called NotUsed, and discarding it. +$CsprojContent = @" + + + NotUsed + Temp project used for creating nupkg file. + $Name.nuspec + $NugetPackageRoot + netcoreapp2.0 + + +"@ + $NupkgPath = Microsoft.PowerShell.Management\Join-Path -Path $NugetPackageRoot -ChildPath "$Name.$Version.nupkg" + + $csprojBasePath = $null + if($script:DotnetCommandPath) { + $csprojBasePath = Microsoft.PowerShell.Management\Join-Path -Path $script:TempPath -ChildPath ([System.Guid]::NewGuid()) + $null = Microsoft.PowerShell.Management\New-Item -Path $csprojBasePath -ItemType Directory -Force -WhatIf:$false -Confirm:$false + $NuspecPath = Microsoft.PowerShell.Management\Join-Path -Path $csprojBasePath -ChildPath "$Name.nuspec" + $CsprojFilePath = Microsoft.PowerShell.Management\Join-Path -Path $csprojBasePath -ChildPath "$Name.csproj" + } + else { + $NuspecPath = Microsoft.PowerShell.Management\Join-Path -Path $NugetPackageRoot -ChildPath "$Name.nuspec" + } + + $tempErrorFile = $null + $tempOutputFile = $null + + try + { + # Remove existing nuspec and nupkg files + if($NupkgPath -and (Test-Path -Path $NupkgPath -PathType Leaf)) + { + Microsoft.PowerShell.Management\Remove-Item $NupkgPath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + } + + if($NuspecPath -and (Test-Path -Path $NuspecPath -PathType Leaf)) + { + Microsoft.PowerShell.Management\Remove-Item $NuspecPath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + } + + Microsoft.PowerShell.Management\Set-Content -Value $nuspec -Path $NuspecPath -Force -Confirm:$false -WhatIf:$false -Encoding UTF8 + + # Create .nupkg file + if($script:DotnetCommandPath) { + Microsoft.PowerShell.Management\Set-Content -Value $CsprojContent -Path $CsprojFilePath -Force -Confirm:$false -WhatIf:$false + + $arguments = @('pack') + $arguments += $csprojBasePath + $arguments += @('--output',$NugetPackageRoot) + $arguments += "/p:StagingPath=$NugetPackageRoot" + $output = & $script:DotnetCommandPath $arguments + Write-Debug -Message "dotnet pack output: $output" + } + elseif($script:NuGetExePath) { + $output = & $script:NuGetExePath pack $NuspecPath -OutputDirectory $NugetPackageRoot + } + + if(-not (Test-Path -Path $NupkgPath -PathType Leaf)) { + $SemanticVersionString = Get-NormalizedVersionString -Version $Version + $NupkgPath = Join-PathUtility -Path $NugetPackageRoot -ChildPath "$Name.$($SemanticVersionString).nupkg" -PathType File + } + + if($LASTEXITCODE -or -not $NupkgPath -or -not (Test-Path -Path $NupkgPath -PathType Leaf)) + { + if($PSArtifactType -eq $script:PSArtifactTypeModule) + { + $message = $LocalizedData.FailedToCreateCompressedModule -f ($output) + $errorId = "FailedToCreateCompressedModule" + } + else + { + $message = $LocalizedData.FailedToCreateCompressedScript -f ($output) + $errorId = "FailedToCreateCompressedScript" + } + + Write-Error -Message $message -ErrorId $errorId -Category InvalidOperation + return + } + + # Publish the .nupkg to gallery + $tempErrorFile = Microsoft.PowerShell.Management\Join-Path -Path $nugetPackageRoot -ChildPath "TempPublishError.txt" + $tempOutputFile = Microsoft.PowerShell.Management\Join-Path -Path $nugetPackageRoot -ChildPath "TempPublishOutput.txt" + + $errorMsg = $null + $outputMsg = $null + $StartProcess_params = @{ + RedirectStandardError = $tempErrorFile + RedirectStandardOutput = $tempOutputFile + NoNewWindow = $true + Wait = $true + PassThru = $true + } + + if($script:DotnetCommandPath) { + $StartProcess_params['FilePath'] = $script:DotnetCommandPath + + $ArgumentList = @('nuget') + $ArgumentList += 'push' + $ArgumentList += "`"$NupkgPath`"" + $ArgumentList += @('--source', "`"$($Destination.TrimEnd('\'))`"") + + if ($PSBoundParameters.Containskey('NugetApiKey')) { + $ArgumentList += @('--api-key', "`"$NugetApiKey`"") + } + } + elseif($script:NuGetExePath) { + $StartProcess_params['FilePath'] = $script:NuGetExePath + + $ArgumentList = @('push') + $ArgumentList += "`"$NupkgPath`"" + $ArgumentList += @('-source', "`"$($Destination.TrimEnd('\'))`"") + $ArgumentList += '-NonInteractive' + if ($PSBoundParameters.Containskey('NugetApiKey')) { + $ArgumentList += @('--api-key', "`"$NugetApiKey`"") + } + } + $StartProcess_params['ArgumentList'] = $ArgumentList + + if($script:IsCoreCLR -and -not $script:IsNanoServer) { + $StartProcess_params['WhatIf'] = $false + $StartProcess_params['Confirm'] = $false + } + + $process = Microsoft.PowerShell.Management\Start-Process @StartProcess_params + + if(Test-Path -Path $tempErrorFile -PathType Leaf) { + $errorMsg = Microsoft.PowerShell.Management\Get-Content -Path $tempErrorFile -Raw + + if($errorMsg) { + Write-Verbose -Message $errorMsg + } + } + + if(Test-Path -Path $tempOutputFile -PathType Leaf) { + $outputMsg = Microsoft.PowerShell.Management\Get-Content -Path $tempOutputFile -Raw + + if($outputMsg) { + Write-Verbose -Message $outputMsg + } + } + + # The newer version of dotnet cli writes the error message into output stream instead of error stream + # Get the error message from output stream when ExitCode is non zero (error). + if($process -and $process.ExitCode -and -not $errorMsg -and $outputMsg) { + $errorMsg = $outputMsg + } + + if(-not $process -or $process.ExitCode) + { + if(($NugetApiKey -eq 'VSTS') -and + ($errorMsg -match 'Cannot prompt for input in non-interactive mode.') ) + { + $errorMsg = $LocalizedData.RegisterVSTSFeedAsNuGetPackageSource -f ($Destination, $script:VSTSAuthenticatedFeedsDocUrl) + } + + if($errorMsg -match 'warn : No API Key was provided and no API Key could be found for *') + { + $errorMsg = $LocalizedData.NuGetApiKeyIsRequiredForNuGetBasedGalleryService -f ($Name, $Destination) + } + + if($PSArtifactType -eq $script:PSArtifactTypeModule) + { + $message = $LocalizedData.FailedToPublish -f ($Name,$errorMsg) + $errorId = "FailedToPublishTheModule" + } + else + { + $message = $LocalizedData.FailedToPublishScript -f ($Name,$errorMsg) + $errorId = "FailedToPublishTheScript" + } + + Write-Error -Message $message -ErrorId $errorId -Category InvalidOperation + } + else + { + if($PSArtifactType -eq $script:PSArtifactTypeModule) + { + $message = $LocalizedData.PublishedSuccessfully -f ($Name, $Destination, $Name) + } + else + { + $message = $LocalizedData.PublishedScriptSuccessfully -f ($Name, $Destination, $Name) + } + + Write-Verbose -Message $message + } + } + finally + { + if($NupkgPath -and (Test-Path -Path $NupkgPath -PathType Leaf)) + { + Microsoft.PowerShell.Management\Remove-Item $NupkgPath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + } + + if($NuspecPath -and (Test-Path -Path $NuspecPath -PathType Leaf)) + { + Microsoft.PowerShell.Management\Remove-Item $NuspecPath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + } + + if($tempErrorFile -and (Test-Path -Path $tempErrorFile -PathType Leaf)) + { + Microsoft.PowerShell.Management\Remove-Item $tempErrorFile -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + } + + if($tempOutputFile -and (Test-Path -Path $tempOutputFile -PathType Leaf)) + { + Microsoft.PowerShell.Management\Remove-Item $tempOutputFile -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + } + + if($csprojBasePath -and (Test-Path -Path $csprojBasePath -PathType Container)) + { + Microsoft.PowerShell.Management\Remove-Item -Path $csprojBasePath -Recurse -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false + } + } +} +>>>>>>> Catch nuget error and diplay localized error instead From 22aba0c0c1e1d39b32e3575efba8816547dbfdfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hei=C3=B0ar=20H=C3=B3lmberg=20J=C3=B3nsson?= Date: Wed, 22 May 2019 17:04:50 +0000 Subject: [PATCH 19/19] fix silly rebase problem --- .../functions/Publish-PSArtifactUtility.ps1 | 487 +----------------- 1 file changed, 1 insertion(+), 486 deletions(-) diff --git a/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 b/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 index 7834d3bf..3c3bffe2 100644 --- a/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 +++ b/src/PowerShellGet/private/functions/Publish-PSArtifactUtility.ps1 @@ -1,487 +1,3 @@ -<<<<<<< HEAD -function Publish-PSArtifactUtility { - [CmdletBinding(PositionalBinding = $false)] - Param - ( - [Parameter(Mandatory = $true, ParameterSetName = 'PublishModule')] - [ValidateNotNullOrEmpty()] - [PSModuleInfo] - $PSModuleInfo, - - [Parameter(Mandatory = $true, ParameterSetName = 'PublishScript')] - [ValidateNotNullOrEmpty()] - [PSCustomObject] - $PSScriptInfo, - - [Parameter(Mandatory = $true, ParameterSetName = 'PublishModule')] - [ValidateNotNullOrEmpty()] - [string] - $ManifestPath, - - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] - $Destination, - - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] - $Repository, - - [Parameter(Mandatory = $false)] - [string] - $NugetApiKey, - - [Parameter(Mandatory = $false)] - [pscredential] - $Credential, - - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string] - $NugetPackageRoot, - - [Parameter(ParameterSetName = 'PublishModule')] - [Version] - $FormatVersion, - - [Parameter(ParameterSetName = 'PublishModule')] - [string] - $ReleaseNotes, - - [Parameter(ParameterSetName = 'PublishModule')] - [string[]] - $Tags, - - [Parameter(ParameterSetName = 'PublishModule')] - [switch] - $SkipAutomaticTags, - - [Parameter(ParameterSetName = 'PublishModule')] - [Uri] - $LicenseUri, - - [Parameter(ParameterSetName = 'PublishModule')] - [Uri] - $IconUri, - - [Parameter(ParameterSetName = 'PublishModule')] - [Uri] - $ProjectUri, - - [Parameter(ParameterSetName = 'PublishModule')] - [string[]] - $Exclude - ) - - Write-Verbose "Calling Publish-PSArtifactUtility" - Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -BootstrapNuGetExe - - $PSArtifactType = $script:PSArtifactTypeModule - $Name = $null - $Description = $null - $Version = "" - $Author = $null - $CompanyName = $null - $Copyright = $null - $requireLicenseAcceptance = "false" - - if ($PSModuleInfo) { - $Name = $PSModuleInfo.Name - $Description = $PSModuleInfo.Description - $Version = $PSModuleInfo.Version - $Author = $PSModuleInfo.Author - $CompanyName = $PSModuleInfo.CompanyName - $Copyright = $PSModuleInfo.Copyright - - if ($PSModuleInfo.PrivateData -and - ($PSModuleInfo.PrivateData.GetType().ToString() -eq "System.Collections.Hashtable") -and - $PSModuleInfo.PrivateData["PSData"] -and - ($PSModuleInfo.PrivateData["PSData"].GetType().ToString() -eq "System.Collections.Hashtable") - ) { - if ( -not $Tags -and $PSModuleInfo.PrivateData.PSData["Tags"]) { - $Tags = $PSModuleInfo.PrivateData.PSData.Tags - } - - if ( -not $ReleaseNotes -and $PSModuleInfo.PrivateData.PSData["ReleaseNotes"]) { - $ReleaseNotes = $PSModuleInfo.PrivateData.PSData.ReleaseNotes - } - - if ( -not $LicenseUri -and $PSModuleInfo.PrivateData.PSData["LicenseUri"]) { - $LicenseUri = $PSModuleInfo.PrivateData.PSData.LicenseUri - } - - if ( -not $IconUri -and $PSModuleInfo.PrivateData.PSData["IconUri"]) { - $IconUri = $PSModuleInfo.PrivateData.PSData.IconUri - } - - if ( -not $ProjectUri -and $PSModuleInfo.PrivateData.PSData["ProjectUri"]) { - $ProjectUri = $PSModuleInfo.PrivateData.PSData.ProjectUri - } - - if ($PSModuleInfo.PrivateData.PSData["Prerelease"]) { - $psmoduleInfoPrereleaseString = $PSModuleInfo.PrivateData.PSData.Prerelease - if ($psmoduleInfoPrereleaseString -and $psmoduleInfoPrereleaseString.StartsWith("-")) { - $Version = [string]$Version + $psmoduleInfoPrereleaseString - } - else { - $Version = [string]$Version + "-" + $psmoduleInfoPrereleaseString - } - } - - if ($PSModuleInfo.PrivateData.PSData["RequireLicenseAcceptance"]) { - $requireLicenseAcceptance = $PSModuleInfo.PrivateData.PSData.requireLicenseAcceptance.ToString().ToLower() - if ($requireLicenseAcceptance -eq "true") { - if ($FormatVersion -and ($FormatVersion.Major -lt $script:PSGetRequireLicenseAcceptanceFormatVersion.Major)) { - $message = $LocalizedData.requireLicenseAcceptanceNotSupported -f ($FormatVersion) - ThrowError -ExceptionName "System.InvalidOperationException" ` - -ExceptionMessage $message ` - -ErrorId "requireLicenseAcceptanceNotSupported" ` - -CallerPSCmdlet $PSCmdlet ` - -ErrorCategory InvalidData - } - - if (-not $LicenseUri) { - $message = $LocalizedData.LicenseUriNotSpecified - ThrowError -ExceptionName "System.InvalidOperationException" ` - -ExceptionMessage $message ` - -ErrorId "LicenseUriNotSpecified" ` - -CallerPSCmdlet $PSCmdlet ` - -ErrorCategory InvalidData - } - - $LicenseFilePath = Join-PathUtility -Path $NugetPackageRoot -ChildPath 'License.txt' -PathType File - if (-not $LicenseFilePath -or -not (Test-Path -Path $LicenseFilePath -PathType Leaf)) { - $message = $LocalizedData.LicenseTxtNotFound - ThrowError -ExceptionName "System.InvalidOperationException" ` - -ExceptionMessage $message ` - -ErrorId "LicenseTxtNotFound" ` - -CallerPSCmdlet $PSCmdlet ` - -ErrorCategory InvalidData - } - - if ((Get-Content -LiteralPath $LicenseFilePath) -eq $null) { - $message = $LocalizedData.LicenseTxtEmpty - ThrowError -ExceptionName "System.InvalidOperationException" ` - -ExceptionMessage $message ` - -ErrorId "LicenseTxtEmpty" ` - -CallerPSCmdlet $PSCmdlet ` - -ErrorCategory InvalidData - } - - #RequireLicenseAcceptance is true, License uri and license.txt exist. Bump Up the FormatVersion - if (-not $FormatVersion) { - $FormatVersion = $script:CurrentPSGetFormatVersion - } - } - elseif ($requireLicenseAcceptance -ne "false") { - $InvalidValueForRequireLicenseAcceptance = $LocalizedData.InvalidValueBoolean -f ($requireLicenseAcceptance, "requireLicenseAcceptance") - Write-Warning -Message $InvalidValueForRequireLicenseAcceptance - } - } - } - } - else { - $PSArtifactType = $script:PSArtifactTypeScript - - $Name = $PSScriptInfo.Name - $Description = $PSScriptInfo.Description - $Version = $PSScriptInfo.Version - $Author = $PSScriptInfo.Author - $CompanyName = $PSScriptInfo.CompanyName - $Copyright = $PSScriptInfo.Copyright - - if ($PSScriptInfo.'Tags') { - $Tags = $PSScriptInfo.Tags - } - - if ($PSScriptInfo.'ReleaseNotes') { - $ReleaseNotes = $PSScriptInfo.ReleaseNotes - } - - if ($PSScriptInfo.'LicenseUri') { - $LicenseUri = $PSScriptInfo.LicenseUri - } - - if ($PSScriptInfo.'IconUri') { - $IconUri = $PSScriptInfo.IconUri - } - - if ($PSScriptInfo.'ProjectUri') { - $ProjectUri = $PSScriptInfo.ProjectUri - } - } - - $nuspecFiles = "" - if ($Exclude) { - $nuspecFileExcludePattern = $Exclude -Join ";" - $nuspecFiles = @{ src = "**/*.*"; exclude = $nuspecFileExcludePattern } - } - - # Add PSModule and PSGet format version tags - if (-not $Tags) { - $Tags = @() - } - - if ($FormatVersion) { - $Tags += "$($script:PSGetFormatVersion)_$FormatVersion" - } - - $DependentModuleDetails = @() - - if ($PSScriptInfo) { - $Tags += "PSScript" - - if ($PSScriptInfo.DefinedCommands -and -not $SkipAutomaticTags) { - if ($PSScriptInfo.DefinedFunctions) { - $Tags += "$($script:Includes)_Function" - $Tags += $PSScriptInfo.DefinedFunctions | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Function)_$_" } - } - - if ($PSScriptInfo.DefinedWorkflows) { - $Tags += "$($script:Includes)_Workflow" - $Tags += $PSScriptInfo.DefinedWorkflows | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Workflow)_$_" } - } - - $Tags += $PSScriptInfo.DefinedCommands | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Command)_$_" } - } - - # Populate the dependencies elements from RequiredModules and RequiredScripts - # - $ValidateAndGetScriptDependencies_Params = @{ - Repository = $Repository - DependentScriptInfo = $PSScriptInfo - CallerPSCmdlet = $PSCmdlet - Verbose = $VerbosePreference - Debug = $DebugPreference - } - if ($PSBoundParameters.ContainsKey('Credential')) { - $ValidateAndGetScriptDependencies_Params.Add('Credential', $Credential) - } - $DependentModuleDetails += ValidateAndGet-ScriptDependencies @ValidateAndGetScriptDependencies_Params - } - else { - $Tags += "PSModule" - - $ModuleManifestHashTable = Get-ManifestHashTable -Path $ManifestPath - - if (-not $SkipAutomaticTags) { - if ($PSModuleInfo.ExportedCommands.Count) { - if ($PSModuleInfo.ExportedCmdlets.Count) { - $Tags += "$($script:Includes)_Cmdlet" - $Tags += $PSModuleInfo.ExportedCmdlets.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Cmdlet)_$_" } - - #if CmdletsToExport field in manifest file is "*", we suggest the user to include all those cmdlets for best practice - if ($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey('CmdletsToExport') -and ($ModuleManifestHashTable.CmdletsToExport -eq "*")) { - $WarningMessage = $LocalizedData.ShouldIncludeCmdletsToExport -f ($ManifestPath) - Write-Warning -Message $WarningMessage - } - } - - if ($PSModuleInfo.ExportedFunctions.Count) { - $Tags += "$($script:Includes)_Function" - $Tags += $PSModuleInfo.ExportedFunctions.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Function)_$_" } - - if ($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey('FunctionsToExport') -and ($ModuleManifestHashTable.FunctionsToExport -eq "*")) { - $WarningMessage = $LocalizedData.ShouldIncludeFunctionsToExport -f ($ManifestPath) - Write-Warning -Message $WarningMessage - } - } - - $Tags += $PSModuleInfo.ExportedCommands.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Command)_$_" } - } - - $dscResourceNames = Get-ExportedDscResources -PSModuleInfo $PSModuleInfo - if ($dscResourceNames) { - $Tags += "$($script:Includes)_DscResource" - - $Tags += $dscResourceNames | Microsoft.PowerShell.Core\ForEach-Object { "$($script:DscResource)_$_" } - - #If DscResourcesToExport is commented out or "*" is used, we will write-warning - if ($ModuleManifestHashTable -and - ($ModuleManifestHashTable.ContainsKey("DscResourcesToExport") -and - $ModuleManifestHashTable.DscResourcesToExport -eq "*") -or - -not $ModuleManifestHashTable.ContainsKey("DscResourcesToExport")) { - $WarningMessage = $LocalizedData.ShouldIncludeDscResourcesToExport -f ($ManifestPath) - Write-Warning -Message $WarningMessage - } - } - - $RoleCapabilityNames = Get-AvailableRoleCapabilityName -PSModuleInfo $PSModuleInfo - if ($RoleCapabilityNames) { - $Tags += "$($script:Includes)_RoleCapability" - - $Tags += $RoleCapabilityNames | Microsoft.PowerShell.Core\ForEach-Object { "$($script:RoleCapability)_$_" } - } - } - - # Populate the module dependencies elements from RequiredModules and - # NestedModules properties of the current PSModuleInfo - $GetModuleDependencies_Params = @{ - PSModuleInfo = $PSModuleInfo - Repository = $Repository - CallerPSCmdlet = $PSCmdlet - Verbose = $VerbosePreference - Debug = $DebugPreference - } - if ($PSBoundParameters.ContainsKey('Credential')) { - $GetModuleDependencies_Params.Add('Credential', $Credential) - } - $DependentModuleDetails = Get-ModuleDependencies @GetModuleDependencies_Params - } - - $dependencies = @() - ForEach ($Dependency in $DependentModuleDetails) { - $ModuleName = $Dependency.Name - $VersionString = "" - - # Version format in NuSpec: - # "[2.0]" --> (== 2.0) Required Version - # "2.0" --> (>= 2.0) Minimum Version - # - # When only MaximumVersion is specified in the ModuleSpecification - # (,1.0] = x <= 1.0 - # - # When both Minimum and Maximum versions are specified in the ModuleSpecification - # [1.0,2.0] = 1.0 <= x <= 2.0 - - if ($Dependency.Keys -Contains "RequiredVersion") { - $VersionString = "[$($Dependency.RequiredVersion)]" - } - elseif ($Dependency.Keys -Contains 'MinimumVersion' -and $Dependency.Keys -Contains 'MaximumVersion') { - $VersionString = "[$($Dependency.MinimumVersion),$($Dependency.MaximumVersion)]" - } - elseif ($Dependency.Keys -Contains 'MaximumVersion') { - $VersionString = "(,$($Dependency.MaximumVersion)]" - } - elseif ($Dependency.Keys -Contains 'MinimumVersion') { - $VersionString = "$($Dependency.MinimumVersion)" - } - - $props = @{ - id = $ModuleName - version = $VersionString - } - - $dependencyObject = New-Object -TypeName PSCustomObject -Property $props - $dependencies += $dependencyObject - } - - $params = @{ - OutputPath = $NugetPackageRoot - Id = $Name - Version = $Version - Authors = $Author - Owners = $CompanyName - Description = $Description - ReleaseNotes = $ReleaseNotes - RequireLicenseAcceptance = ($requireLicenseAcceptance -eq $true) - Copyright = $Copyright - Tags = $Tags - LicenseUrl = $LicenseUri - ProjectUrl = $ProjectUri - IconUrl = $IconUri - Dependencies = $dependencies - } - - if ($nuspecFiles) { - $params.Add('Files', $nuspecFiles) - } - - try { - $NuspecFullName = New-NuspecFile @params - } - catch { - Write-Error -Message "Failed to create nuspec file $_.Exception" -ErrorAction Stop - } - - try { - if ($DotnetCommandPath) { - $NupkgFullName = New-NugetPackage -NuspecPath $NuspecFullName -NugetPackageRoot $NugetPackageRoot -UseDotnetCli -Verbose:$VerbosePreference - } - elseif ($NuGetExePath) { - $NupkgFullName = New-NugetPackage -NuspecPath $NuspecFullName -NugetPackageRoot $NugetPackageRoot -NugetExePath $NuGetExePath -Verbose:$VerbosePreference - } - - <<<<<<< HEAD - Write-Verbose -Message "Successfully created nuget package at $NupkgFullName" - } - catch { - if ($PSArtifactType -eq $script:PSArtifactTypeModule) { - $message = $LocalizedData.FailedToCreateCompressedModule -f ($_.Exception.message) - $errorId = "FailedToCreateCompressedModule" - ======= - if ($script:DotnetCommandPath) { - $StartProcess_params['FilePath'] = $script:DotnetCommandPath - - $ArgumentList = @('nuget') - $ArgumentList += 'push' - $ArgumentList += "`"$NupkgPath`"" - $ArgumentList += @('--source', "`"$($Destination.TrimEnd('\'))`"") - - if ($PSBoundParameters.Containskey('NugetApiKey')) { - $ArgumentList += @('--api-key', "`"$NugetApiKey`"") - } - } - elseif ($script:NuGetExePath) { - $StartProcess_params['FilePath'] = $script:NuGetExePath - - $ArgumentList = @('push') - $ArgumentList += "`"$NupkgPath`"" - $ArgumentList += @('-source', "`"$($Destination.TrimEnd('\'))`"") - $ArgumentList += '-NonInteractive' - if ($PSBoundParameters.Containskey('NugetApiKey')) { - $ArgumentList += @('--api-key', "`"$NugetApiKey`"") - } - >>>>>>> Remove validation on NugetApiKey parameter - } - else { - $message = $LocalizedData.FailedToCreateCompressedScript -f ($_.Exception.message) - $errorId = "FailedToCreateCompressedScript" - } - - Write-Error -Message $message -ErrorId $errorId -Category InvalidOperation -ErrorAction Stop - } - - try { - if ($DotnetCommandPath) { - Publish-NugetPackage -NupkgPath $NupkgFullName -Destination $Destination -NugetApiKey $NugetApiKey -UseDotnetCli -Verbose:$VerbosePreference - } - if ($NuGetExePath) { - Publish-NugetPackage -NupkgPath $NupkgFullName -Destination $Destination -NugetApiKey $NugetApiKey -NugetExePath $NuGetExePath -Verbose:$VerbosePreference - } - - if ($PSArtifactType -eq "Module") { - $message = $LocalizedData.PublishedSuccessfully -f ($Name, $Destination, $Name) - } - if ($PSArtifactType -eq "Script") { - $message = $LocalizedData.PublishedScriptSuccessfully -f ($Name, $Destination, $Name) - } - - Write-Verbose -Message $message - } - catch { - if ( $NugetApiKey -eq "VSTS" -and ($_.Exception.Message -match "Cannot prompt for input in non-interactive mode.")) { - $message = $LocalizedData.RegisterVSTSFeedAsNuGetPackageSource -f ($Destination, $script:VSTSAuthenticatedFeedsDocUrl) - } - else { - $message = $_.Exception.message - } - - if ($PSArtifactType -eq "Module") { - $errorMessage = $LocalizedData.FailedToPublish -f ($Name, $message) - $errorId = "FailedToPublishTheModule" - } - - if ($PSArtifactType -eq "Script") { - $errorMessage = $LocalizedData.FailedToPublishScript -f ($Name, $message) - $errorId = "FailedToPublishTheScript" - } - - Write-Error -Message $errorMessage -ErrorId $errorId -Category InvalidOperation -ErrorAction Stop - } - } -======= function Publish-PSArtifactUtility { [CmdletBinding(PositionalBinding=$false)] @@ -1128,5 +644,4 @@ $CsprojContent = @" Microsoft.PowerShell.Management\Remove-Item -Path $csprojBasePath -Recurse -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false } } -} ->>>>>>> Catch nuget error and diplay localized error instead +} \ No newline at end of file