Tasks/Publish.PowerShellUniversal.build.ps1
|
param ( [Parameter()] [System.String] $OutputDirectory = (property OutputDirectory (Join-Path -Path $BuildRoot -ChildPath 'output')), [Parameter()] [System.String] $UniversalServerUrl = (property UniversalServerUrl ''), [Parameter()] [System.String] $UniversalServerAppToken = (property UniversalServerAppToken ''), [Parameter()] [System.String] $UniversalPSResourceRepositoryName = (property UniversalPSResourceRepositoryName ''), [Parameter()] [System.String] $UniversalPSResourceRepositoryUrl = (property UniversalPSResourceRepositoryUrl ''), [Parameter()] [System.Boolean] $UniversalPSResourceRepositoryAutoRemove = (property UniversalPSResourceRepositoryAutoRemove $true), [Parameter()] [System.String] $UniversalRepositoryStagingDirectoryName = (property UniversalRepositoryStagingDirectoryName 'PsuRepository'), [Parameter()] [System.String] $UniversalRepositoryZipName = (property UniversalRepositoryZipName ''), [Parameter()] [System.Boolean] $UniversalRepositoryAsModule = (property UniversalRepositoryAsModule $false), [Parameter()] [System.Boolean] $UniversalUnpinned = (property UniversalUnpinned $true), [Parameter()] [ValidateRange(0, 300)] [System.Int32] $UniversalDeploymentNotificationDelaySeconds = (property UniversalDeploymentNotificationDelaySeconds 2), [Parameter()] [ValidateRange(1, 3600)] [System.Int32] $UniversalDeploymentNotificationLookbackSeconds = (property UniversalDeploymentNotificationLookbackSeconds 120), [Parameter()] [System.String] $UniversalDeploymentNotificationFilter = (property UniversalDeploymentNotificationFilter ''), [Parameter()] [System.Collections.Hashtable] $BuildInfo = (property BuildInfo @{ }) ) $TaskParameterNames = @($PSBoundParameters.Keys) # Synopsis: Upload the packed module directly to the PowerShell Universal deployment endpoint. task publish_packed_module_to_universal_server { # Get the values for task variables, see https://github.com/gaelcolas/Sampler?tab=readme-ov-file#build-task-variables. . Set-SamplerTaskVariable $secretsPath = Join-Path -Path $BuildRoot -ChildPath 'secrets.local.ps1' if (Test-Path -Path $secretsPath) { . $secretsPath } $configurationParameters = @{ BuildInfo = $BuildInfo ServerUrl = $UniversalServerUrl AppToken = $UniversalServerAppToken RepositoryName = $UniversalPSResourceRepositoryName RepositoryUrl = $UniversalPSResourceRepositoryUrl RepositoryAutoRemove = $UniversalPSResourceRepositoryAutoRemove Unpinned = $UniversalUnpinned RepositoryAutoRemoveWasBound = 'UniversalPSResourceRepositoryAutoRemove' -in $TaskParameterNames UnpinnedWasBound = 'UniversalUnpinned' -in $TaskParameterNames } $configuration = Sampler.PowerShellUniversalTasks\Resolve-UniversalServerConfiguration @configurationParameters $packagePath = Join-Path -Path $OutputDirectory -ChildPath ('{0}.{1}.nupkg' -f $ProjectName, $ModuleVersion) $endpoint = '{0}/api/v1/deployment/module/{1}/{2}?repository=output&synchronous=true' -f @( $configuration.ServerUrl $ProjectName $ModuleVersion ) $script:UniversalDeploymentStartedAt = [System.DateTimeOffset]::UtcNow $null = Sampler.PowerShellUniversalTasks\Invoke-UniversalDeploymentUpload -Uri $endpoint -AppToken $configuration.AppToken -Path $packagePath Write-Build -Color Green -Text ("Published module '{0}' version '{1}' to PowerShell Universal." -f $ProjectName, $ModuleVersion) } # Synopsis: Reconcile a PowerShell resource repository on the server and install the built module from it. task publish_module_from_psresource_repos_to_universal_server { # Get the values for task variables, see https://github.com/gaelcolas/Sampler?tab=readme-ov-file#build-task-variables. . Set-SamplerTaskVariable $secretsPath = Join-Path -Path $BuildRoot -ChildPath 'secrets.local.ps1' if (Test-Path -Path $secretsPath) { . $secretsPath } $configurationParameters = @{ BuildInfo = $BuildInfo ServerUrl = $UniversalServerUrl AppToken = $UniversalServerAppToken RepositoryName = $UniversalPSResourceRepositoryName RepositoryUrl = $UniversalPSResourceRepositoryUrl RepositoryAutoRemove = $UniversalPSResourceRepositoryAutoRemove Unpinned = $UniversalUnpinned RepositoryAutoRemoveWasBound = 'UniversalPSResourceRepositoryAutoRemove' -in $TaskParameterNames UnpinnedWasBound = 'UniversalUnpinned' -in $TaskParameterNames RequireRepository = $true } $configuration = Sampler.PowerShellUniversalTasks\Resolve-UniversalServerConfiguration @configurationParameters $repositoryUrl = $configuration.RepositoryUrl if ($repositoryUrl -notmatch '^[a-z][a-z0-9+.-]*://') { $repositoryUrl = Get-SamplerAbsolutePath -Path $repositoryUrl -RelativeTo $BuildRoot $null = New-Item -Path $repositoryUrl -ItemType Directory -Force } $installParameters = @{ ServerUrl = $configuration.ServerUrl AppToken = $configuration.AppToken ModuleName = $ProjectName ModuleVersion = $ModuleVersion RepositoryName = $configuration.RepositoryName RepositoryUrl = $repositoryUrl RepositoryAutoRemove = $configuration.RepositoryAutoRemove } $script:UniversalDeploymentStartedAt = [System.DateTimeOffset]::UtcNow Sampler.PowerShellUniversalTasks\Install-UniversalModuleFromRepository @installParameters Write-Build -Color Green -Text ("Installed module '{0}' version '{1}' from repository '{2}'." -f $ProjectName, $ModuleVersion, $configuration.RepositoryName) } # Synopsis: Package the built module and its dependencies as an offline PowerShell Universal automation repository. task package_universal_automation_repository { # Get the values for task variables, see https://github.com/gaelcolas/Sampler?tab=readme-ov-file#build-task-variables. . Set-SamplerTaskVariable if (-not $BuiltModuleManifest) { throw "No valid manifest found for project '$ProjectName'. Run the build task first." } $packageParameters = @{ BuiltModuleManifest = $BuiltModuleManifest OutputDirectory = $OutputDirectory ModuleVersion = $ModuleVersion StagingDirectoryName = $UniversalRepositoryStagingDirectoryName ZipName = $UniversalRepositoryZipName } $package = Sampler.PowerShellUniversalTasks\New-UniversalAutomationRepositoryPackage @packageParameters -Confirm:$false Write-Build -Color Green -Text ("Packaged the PowerShell Universal automation repository at '{0}'." -f $package.FullName) } # Synopsis: Upload an offline automation repository package to the PowerShell Universal deployment endpoint. task publish_universal_automation_repository_to_server { # Get the values for task variables, see https://github.com/gaelcolas/Sampler?tab=readme-ov-file#build-task-variables. . Set-SamplerTaskVariable $secretsPath = Join-Path -Path $BuildRoot -ChildPath 'secrets.local.ps1' if (Test-Path -Path $secretsPath) { . $secretsPath } $configurationParameters = @{ BuildInfo = $BuildInfo ServerUrl = $UniversalServerUrl AppToken = $UniversalServerAppToken RepositoryName = $UniversalPSResourceRepositoryName RepositoryUrl = $UniversalPSResourceRepositoryUrl RepositoryAutoRemove = $UniversalPSResourceRepositoryAutoRemove Unpinned = $UniversalUnpinned RepositoryAutoRemoveWasBound = 'UniversalPSResourceRepositoryAutoRemove' -in $TaskParameterNames UnpinnedWasBound = 'UniversalUnpinned' -in $TaskParameterNames } $configuration = Sampler.PowerShellUniversalTasks\Resolve-UniversalServerConfiguration @configurationParameters $zipName = if ([System.String]::IsNullOrWhiteSpace($UniversalRepositoryZipName)) { '{0}.{1}.zip' -f $ProjectName, $ModuleVersion } else { $UniversalRepositoryZipName } $packagePath = Join-Path -Path $OutputDirectory -ChildPath $zipName $endpoint = '{0}/api/v1/deployment?asModule={1}&unpinned={2}' -f @( $configuration.ServerUrl $UniversalRepositoryAsModule.ToString().ToLowerInvariant() $configuration.Unpinned.ToString().ToLowerInvariant() ) $script:UniversalDeploymentStartedAt = [System.DateTimeOffset]::UtcNow $deployment = Sampler.PowerShellUniversalTasks\Invoke-UniversalDeploymentUpload -Uri $endpoint -AppToken $configuration.AppToken -Path $packagePath Write-Build -Color Green -Text ("Deployed automation repository '{0}' version '{1}'." -f $deployment.name, $deployment.version) } # Synopsis: Fail the build when PowerShell Universal reports a deployment error notification. task assert_universal_deployment_succeeded { # Get the values for task variables, see https://github.com/gaelcolas/Sampler?tab=readme-ov-file#build-task-variables. . Set-SamplerTaskVariable $secretsPath = Join-Path -Path $BuildRoot -ChildPath 'secrets.local.ps1' if (Test-Path -Path $secretsPath) { . $secretsPath } $configurationParameters = @{ BuildInfo = $BuildInfo ServerUrl = $UniversalServerUrl AppToken = $UniversalServerAppToken RepositoryName = $UniversalPSResourceRepositoryName RepositoryUrl = $UniversalPSResourceRepositoryUrl RepositoryAutoRemove = $UniversalPSResourceRepositoryAutoRemove Unpinned = $UniversalUnpinned RepositoryAutoRemoveWasBound = 'UniversalPSResourceRepositoryAutoRemove' -in $TaskParameterNames UnpinnedWasBound = 'UniversalUnpinned' -in $TaskParameterNames } $configuration = Sampler.PowerShellUniversalTasks\Resolve-UniversalServerConfiguration @configurationParameters $universalServer = $BuildInfo.UniversalServer if ($UniversalDeploymentNotificationDelaySeconds -eq 2 -and $null -ne $universalServer.UniversalDeploymentNotificationDelaySeconds) { $UniversalDeploymentNotificationDelaySeconds = [System.Convert]::ToInt32( $universalServer.UniversalDeploymentNotificationDelaySeconds ) } if ($UniversalDeploymentNotificationLookbackSeconds -eq 120 -and $null -ne $universalServer.UniversalDeploymentNotificationLookbackSeconds) { $UniversalDeploymentNotificationLookbackSeconds = [System.Convert]::ToInt32( $universalServer.UniversalDeploymentNotificationLookbackSeconds ) } if ([System.String]::IsNullOrWhiteSpace($UniversalDeploymentNotificationFilter) -and -not [System.String]::IsNullOrWhiteSpace($universalServer.UniversalDeploymentNotificationFilter)) { $UniversalDeploymentNotificationFilter = [System.String] $universalServer.UniversalDeploymentNotificationFilter } if ($UniversalDeploymentNotificationDelaySeconds -lt 0 -or $UniversalDeploymentNotificationDelaySeconds -gt 300) { throw 'UniversalDeploymentNotificationDelaySeconds must be between 0 and 300.' } if ($UniversalDeploymentNotificationLookbackSeconds -lt 1 -or $UniversalDeploymentNotificationLookbackSeconds -gt 3600) { throw 'UniversalDeploymentNotificationLookbackSeconds must be between 1 and 3600.' } if ($UniversalDeploymentNotificationDelaySeconds -gt 0) { Write-Build -Color DarkGray -Text ("Waiting {0} second(s) for deployment notifications." -f $UniversalDeploymentNotificationDelaySeconds) Start-Sleep -Seconds $UniversalDeploymentNotificationDelaySeconds } $notificationSince = $script:UniversalDeploymentStartedAt if (-not $notificationSince) { $notificationSince = [System.DateTimeOffset]::UtcNow.AddSeconds(-$UniversalDeploymentNotificationLookbackSeconds) Write-Build -Color Yellow -Text ("Deployment start time was not recorded. Checking the last {0} second(s)." -f $UniversalDeploymentNotificationLookbackSeconds) } $notificationFilter = $UniversalDeploymentNotificationFilter $errorParameters = @{ ServerUrl = $configuration.ServerUrl AppToken = $configuration.AppToken Since = $notificationSince FilterText = $notificationFilter } $deploymentErrors = @(Sampler.PowerShellUniversalTasks\Get-UniversalDeploymentError @errorParameters) if ($deploymentErrors.Count -gt 0) { $errorSummary = $deploymentErrors | ForEach-Object -Process { '[{0}] [{1}] {2}: {3}' -f $_.CreatedTime, $_.Level, $_.Title, $_.Description } Write-Build -Color Red -Text 'PowerShell Universal deployment validation failed:' foreach ($errorMessage in $errorSummary) { Write-Build -Color Red -Text (" {0}" -f $errorMessage) } $failureMessage = 'PowerShell Universal deployment validation failed after {0}:{1}{2}' -f @( $notificationSince [System.Environment]::NewLine ($errorSummary -join [System.Environment]::NewLine) ) throw $failureMessage } Write-Build -Color Green -Text ("No PowerShell Universal deployment error notifications were found after {0}." -f $notificationSince) } # Synopsis: Install the module from a PSU resource repository and validate deployment notifications. task publish_psu_pull_module_from_psresourcerepo publish_module_from_psresource_repos_to_universal_server, assert_universal_deployment_succeeded # Synopsis: Package and deploy an offline PSU automation repository and validate deployment notifications. task publish_psu_push_repository package_universal_automation_repository, publish_universal_automation_repository_to_server, assert_universal_deployment_succeeded |