VirtualEngine / Lability

Virtual Engine test lab deployment and configuration module
MIT License
282 stars 50 forks source link

Add supported for Azure DevOps Artifact private feeds #419

Closed bm-fez closed 1 year ago

bm-fez commented 1 year ago

Fixes #421

Add support for downloading DSC modules to the virtualisation/modules from a private Azure DevOps Artifact feed

Note:

bm-fez commented 1 year ago

@iainbrighton do you need me to do any more changes for this PR?

iainbrighton commented 1 year ago

@iainbrighton do you need me to do any more changes for this PR?

@bm-fez No, it's OK. I'll take a look - it's my first day back in the office after some time off.

bm-fez commented 1 year ago

I will look at those two items ASAP

iainbrighton commented 1 year ago

Hi @bm-fez

Can you try updating the Resolve-AzDoModuleUri function to this code and test it?

function Resolve-AzDoModuleUri {
 <#
    .SYNOPSIS
        Returns the direct download Uri for a PowerShell module hosted
        on the Azure DevOps Artifacts.
#>
    [CmdletBinding()]
    [OutputType([System.String])]
    param (
        ## PowerShell DSC resource module name
        [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [ValidateNotNullOrEmpty()]
        [System.String] $Name,

        ## The minimum version of the DSC module required
        [Parameter(ValueFromPipelineByPropertyName)]
        [ValidateNotNullOrEmpty()]
        [System.Version] $MinimumVersion,

        ## The exact version of the DSC module required
        [Parameter(ValueFromPipelineByPropertyName)]
        [ValidateNotNullOrEmpty()]
        [System.Version] $RequiredVersion,

        ## Direct download Uri
        [Parameter(ValueFromPipelineByPropertyName)]
        [ValidateNotNullOrEmpty()]
        [System.String] $Uri,

        [Parameter(ValueFromPipelineByPropertyName)]
        [AllowNull()]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.CredentialAttribute()]
        $FeedCredential,

        ## Catch all, for splatting $PSBoundParameters
        [Parameter(ValueFromRemainingArguments)]
        $RemainingArguments
    )
    process {

        if ($PSBoundParameters.ContainsKey('Uri')) {

            $psRepositoryUri = $Uri;
        }
        else {

            $psRepositoryUri = (Get-ConfigurationData -Configuration Host).RepositoryUri;
        }

        if ($PSBoundParameters.ContainsKey('RequiredVersion')) {
           ## Download the specific version
           return ('{0}?id={1}&version={2}' -f $psRepositoryUri, $Name.ToLower(), $RequiredVersion)
        }
        else {

            ## Find the latest package versions
            $invokeRestMethodParams = @{
                Uri = "{0}/FindPackagesById()?id='{1}'" -f $psRepositoryUri, $Name.ToLower()
            }
            if ($PSBoundParameters.ContainsKey('FeedCredential'))
            {
                $invokeRestMethodParams['Credential'] = $FeedCredential
            }
            $azDoPackages = Invoke-RestMethod @invokeRestMethodParams

            ## Find and return the latest version
            $lastestDoPackageVersion = $azDoPackages | ForEach-Object {
                $_.properties.NormalizedVersion -as [System.Version] } |
                    Sort-Object | Select-Object -Last 1
            return ('{0}?id={1}&version={2}' -f $psRepositoryUri, $Name.ToLower(), $lastestDoPackageVersion.ToString())
        }

    } #end process
} #end function Resolve-AzDoModuleUri.ps1

It appears to work in my limited testing but your mileage may vary.

Thanks, Iain

bm-fez commented 1 year ago

@iainbrighton your suggestion for the getting the newest version of a module works. Shame we cannot go it in a single API call (I have asked the AzDo PG if there is a non-documented way, but who knows when I get an answer and if it helps us)

The only change I had to make to your code was on the required version URL

return ('{0}?id={1}&version={2}' -f $psRepositoryUri, $Name.ToLower(), $RequiredVersion)

Works fine if 3 part SEMVER versions are used, but we have some historic modules with 4 part numbering. The strange thing is that even though they appear in the Azure Artifacts UI as a 4 part number you can only download the file using the first 3 parts of the number. If you use 4 part you get a 404 error.

So I needed to use

return ('{0}?id={1}&version={2}' -f $psRepositoryUri, $Name.ToLower(), "$($RequiredVersion.Major).$($RequiredVersion.Minor).$($RequiredVersion.Build)")

iainbrighton commented 1 year ago

The only change I had to make to your code was on the required version URL

return ('{0}?id={1}&version={2}' -f $psRepositoryUri, $Name.ToLower(), $RequiredVersion)

Works fine if 3 part SEMVER versions are used, but we have some historic modules with 4 part numbering. The strange thing is that even though they appear in the Azure Artifacts UI as a 4 part number you can only download the file using the first 3 parts of the number. If you use 4 part you get a 404 error.

So I needed to use

return ('{0}?id={1}&version={2}' -f $psRepositoryUri, $Name.ToLower(), "$($RequiredVersion.Major).$($RequiredVersion.Minor).$($RequiredVersion.Build)")

If that's how it is then I am happy with this. Thanks for the contribution!

bm-fez commented 1 year ago

@iainbrighton glad we got there in the end, an happy to contribute.

Any idea yet as to how this PR fits into your plan for the next public release?

iainbrighton commented 1 year ago

@bm-fez v0.24.0 has been published to the PSGallery 😃

bm-fez commented 1 year ago

@bm-fez v0.24.0 has been published to the PSGallery 😃

I have just done an end to end test of v0.24.0 and it is work perfectly 👍