Open adilio opened 2 years ago
oh, fantastic! totally
Having this need I tested a possible solution by modifying the main.ps1 script:
As I don't know how to pass a list of structured information to the Action as a parameter, I previously configured my repositories in a dedicated step. Once registered, the repositories are accessible in the main.ps1 script, it remains to find the repository in which each module is located:
$RepositoryNames=Get-PSRepository|Select-Object -ExpandProperty Name
...
Write-Output "Saving module $module on $psshell to $modpath"
$item, $version = $module.Split(":")
if ($version) {
$Repository=(Find-Module -Name $Item -RequiredVersion $version -Repository $RepositoryNames).Repository
Write-Output "`tModule $module on $psshell found in '$Repository'"
Save-Module $item -Repository $Repository -RequiredVersion $version -ErrorAction Stop -Force:$force -AllowPrerelease:$allowprerelease -Path $modpath
} else {
$Repository=(Find-Module -Name $Item -Repository $RepositoryNames).Repository
Write-Output "`tModule $module on $psshell found in '$Repository'"
Save-Module $item -Repository $Repository -ErrorAction Stop -Force:$force -AllowPrerelease:$allowprerelease -Path $modpath
}
I have not tested with PSCore nor the case where there is a collision (the same module exists in two repositories). By default, I assume PsGallery is configured. In the case where only PsGallery exists, for the moment we will uselessly search the repository.
It remains to be tested.
Find-Module can use the 'AllowPrerelease' parameter :
if ($version) {
#todo collision présent dans les deux -> 2 résultats
#todo PScore
$Repository=(Find-Module -Name $Item -RequiredVersion $version -AllowPrerelease:$allowprerelease -Repository $RepositoryNames ).Repository
Write-Output "`tModule $module on $psshell found in '$Repository'"
Save-Module $item -Repository $Repository -RequiredVersion $version -ErrorAction Stop -Force:$force -AllowPrerelease:$allowprerelease -Path $modpath
} else {
$Repository=(Find-Module -Name $Item -AllowPrerelease:$allowprerelease -Repository $RepositoryNames).Repository
Write-Output "`tModule $module on $psshell found in '$Repository'"
Save-Module $item -Repository $Repository -ErrorAction Stop -Force:$force -AllowPrerelease:$allowprerelease -Path $modpath
}
I tested a repository requiring credentials:
At the moment the PR code (vNext5.0) could only have one repository with credential. The following line:
Find-Module -Name Etsdatetime -Repository $RepositoryNames -allowprerelease -Credential $credential
only uses the credential if one of the repositories asks for one. Otherwise, we see that the cmdlet does not take into account the -Credential parameter.
Managing multiple repositories with credential will require a bit more testing and the simplest possible implementation...
>>the simplest possible implementation... I'm not sure that's the case
1- In a dedicated configuration step: The user declares the secret(s) (account and password) for each repository requiring credentials
$Credential=New-Object PSCredential('${{ secrets.CLOUDSMITHACCOUNTNAME }}',$(ConvertTo-SecureString '${{ secrets.CLOUDSMITHPASSWORD }}' -AsPlainText -Force) )
Then he has to create a hashtable where each key name is a repository name and the associated value is a credential object:
$RepositoriesCredential.'MyRepoName'=$Credential
The user configures the repository or repositories, those requiring credentials reuse previously created objects.
The user must define a file name:
$RepositoriesAuthenticationFileName='RepositoriesCredential.Datas.ps1xml'
then create the 'PSModuleCacheCredentialFileName' environment variable (this name is mandatory):
echo "PSModuleCacheCredentialFileName=$RepositoriesAuthenticationFileName" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append
Finally the user saves the hashtable type object:
$RepositoriesCredential | Export-CliXml -Path (Join-Path $home -ChildPath $RepositoriesAuthenticationFileName)
2- In Action.YML (PSModuleCache) we add a parameter 'UseRepositoriesWithCredential' (default 'false') indicating whether the action must manage credentials when calling Find-Module and Save-Module In his Powershell code we get the filename via the environment variable declared by the user:
$Parameters=@{
Modules="${{ inputs.modules-to-cache }}"
RepositoriesAuthenticationFileName=$Env:PSModuleCacheCredentialFileName
...
The code in PSModuleCache.psm1 can then retrieve the hashtable (with the original .Net types). Once this is done, we can find the credentials associated with the existing repository names in the session:
$RepositoriesWithCredential=Import-CliXml -Path (Join-Path $home -ChildPath $ModuleCache.RepositoriesAuthenticationFileName) }
...
if ($RepositoryName -in $RepositoriesWithCredential.Keys)
{
$PSBoundParameters.Credential=$RepositoriesWithCredential."$RepositoryName"
}
This approach is Powershell based, I haven't explored other possibilities. In all cases it is the user, and not the action, who knows the information needed to be recorded. On the other hand, the Action must know the file name 'ps1xml' and it forces the user to use the same environment variable name.
Notes about one exception raised by Find-Module
We therefore do not know the real cause of the error.
Example :
Repository configuration :
>>I haven't explored other possibilities.
We can perhaps remove the use of the filename if we serialize the hashtable and assign a string to the environment variable:
$PsRepositoriesCredential=[Management.Automation.PSSerializer]::Serialize( $RepositoriesCredential,3)
echo "PSModuleCacheCredentials=$PsRepositoriesCredential" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append
To check ( update Seems impossible or requires special formatting which I couldn't find).
For information: If the credentials are wrong, the registration of the repository fails but with an inappropriate error message :
Register-PSRepository : The specified Uri 'https://nuget.cloudsmith.io/test-YJy/psmodulecache/v2/' for parameter
'SourceLocation' is an invalid Web Uri. Please ensure that it meets the Web Uri requirements.
See https://github.com/PowerShell/PowerShellGet/issues/23
If the account name is wrong but the password is valid, this does not seem to be a problem for Register-PSRepository, Find-Module and Save-Module. I don't know if CloudSmith is behaving this way or PowershellGet is acting up.
Finally, if the credentials are wrong and they are used with Find-Module, this triggers the famous catch-all exception :
PackageManagement\Find-Package : No match was found for the specified search criteria and module name 'EtsDatetime'.
Try Get-PSRepository to see all available registered module repositories.
Once again we know that the call does not work but we do not know why.
I added checks around the user created hashtable.
Heya @potatoqualitee 👋🏼 !
I believe it would be very useful if this action could support the ability to specify a custom/private repository as the module source. A LOT of organizations write or at least customize their own PowerShell modules, that are only available via internal repos.
Having the ability to specify repo URI and creds, possibly via an optional input, would mean more orgs could adopt this action in their pipelines.
I'm happy to work on this, if assigned and acceptable?