Private/GitHub/Get-CgrGitHubReleaseSelection.ps1
|
function Get-CgrGitHubReleaseSelection { [CmdletBinding()] param( [Parameter(Mandatory)] [psobject] $Repository, [string[]] $ReleaseTag, [string[]] $ReleaseExcludeTag, [switch] $IncludePrerelease, [switch] $IncludeDraftReleases, [ValidateRange(1, [int]::MaxValue)] [int] $ReleaseCount, [ValidateNotNullOrEmpty()] [string] $HostName = 'github.com' ) $listResult = Invoke-CgrGitHubApiReadRequest ` -ArgumentList @( 'api', '--hostname', $HostName, '--paginate', '--slurp', "repos/$($Repository.FullName)/releases?per_page=100" ) if ($listResult.ExitCode -ne 0) { $diagnostic = Protect-CgrDiagnosticText -Text ([string] $listResult.ErrorText) $message = "GitHub CLI failed to enumerate releases for '$($Repository.FullName)'. $diagnostic" $exception = [System.InvalidOperationException]::new($message.Trim()) $errorRecord = [System.Management.Automation.ErrorRecord]::new( $exception, 'SourceGitHubReleaseEnumerationFailed', [System.Management.Automation.ErrorCategory]::ReadError, $Repository.FullName ) $PSCmdlet.ThrowTerminatingError($errorRecord) } $json = ($listResult.Output | ForEach-Object { [string] $_ }) -join "`n" $pages = if ([string]::IsNullOrWhiteSpace($json)) { @() } else { @($json | ConvertFrom-Json -Depth 100) } $available = [System.Collections.Generic.List[object]]::new() foreach ($page in $pages) { foreach ($release in @($page)) { if ($null -ne $release) { $available.Add($release) } } } $latestReleaseId = $null $latestReleaseTag = $null $latestResult = Invoke-CgrGitHubApiReadRequest ` -ArgumentList @('api', '--hostname', $HostName, "repos/$($Repository.FullName)/releases/latest") if ($latestResult.ExitCode -eq 0) { $latestJson = ($latestResult.Output | ForEach-Object { [string] $_ }) -join "`n" if (-not [string]::IsNullOrWhiteSpace($latestJson)) { $latestRelease = $latestJson | ConvertFrom-Json -Depth 100 $latestReleaseId = $latestRelease.id $latestReleaseTag = [string] $latestRelease.tag_name } } elseif ([string] $latestResult.ErrorText -notmatch '(?i)404|not found') { $diagnostic = Protect-CgrDiagnosticText -Text ([string] $latestResult.ErrorText) $message = "GitHub CLI failed to determine the latest release for '$($Repository.FullName)'. $diagnostic" $exception = [System.InvalidOperationException]::new($message.Trim()) $errorRecord = [System.Management.Automation.ErrorRecord]::new( $exception, 'SourceGitHubLatestReleaseReadFailed', [System.Management.Automation.ErrorCategory]::ReadError, $Repository.FullName ) $PSCmdlet.ThrowTerminatingError($errorRecord) } $selected = @($available) if (-not $IncludeDraftReleases) { $selected = @($selected | Where-Object { -not [bool] $_.draft }) } if (-not $IncludePrerelease) { $selected = @($selected | Where-Object { -not [bool] $_.prerelease }) } if ($ReleaseTag -and $ReleaseTag.Count -gt 0) { $selected = @($selected | Where-Object { $tagName = [string] $_.tag_name foreach ($pattern in $ReleaseTag) { if ($tagName -like $pattern) { return $true } } return $false }) } if ($ReleaseExcludeTag -and $ReleaseExcludeTag.Count -gt 0) { $selected = @($selected | Where-Object { $tagName = [string] $_.tag_name foreach ($pattern in $ReleaseExcludeTag) { if ($tagName -like $pattern) { return $false } } return $true }) } $selected = @($selected | Sort-Object -Property @{ Expression = { if ($_.published_at) { [datetimeoffset] $_.published_at } elseif ($_.created_at) { [datetimeoffset] $_.created_at } else { [datetimeoffset]::MinValue } }; Descending = $true }, @{ Expression = { [string] $_.tag_name }; Descending = $false }) if ($PSBoundParameters.ContainsKey('ReleaseCount')) { $selected = @($selected | Select-Object -First $ReleaseCount) } $normalized = [System.Collections.Generic.List[object]]::new() foreach ($release in $selected) { $tagName = [string] $release.tag_name if ([string]::IsNullOrWhiteSpace($tagName)) { $message = "Source release id '$($release.id)' does not have a tag name and cannot be selected safely." $exception = [System.InvalidOperationException]::new($message) $errorRecord = [System.Management.Automation.ErrorRecord]::new( $exception, 'SourceGitHubReleaseTagMissing', [System.Management.Automation.ErrorCategory]::InvalidData, $release.id ) $PSCmdlet.ThrowTerminatingError($errorRecord) } $commitResult = Invoke-CgrGitHubApiReadRequest ` -ArgumentList @('api', '--hostname', $HostName, "repos/$($Repository.FullName)/commits/$([uri]::EscapeDataString($tagName))", '--jq', '.sha') if ($commitResult.ExitCode -ne 0) { $diagnostic = Protect-CgrDiagnosticText -Text ([string] $commitResult.ErrorText) $message = "Source release tag '$tagName' does not resolve to a commit and cannot be selected safely. $diagnostic" $exception = [System.InvalidOperationException]::new($message.Trim()) $errorRecord = [System.Management.Automation.ErrorRecord]::new( $exception, 'SourceGitHubReleaseTagResolutionFailed', [System.Management.Automation.ErrorCategory]::InvalidResult, $tagName ) $PSCmdlet.ThrowTerminatingError($errorRecord) } $assets = @($release.assets | ForEach-Object { [pscustomobject] @{ Id = $_.id Name = [string] $_.name Label = [string] $_.label Size = [long] $_.size ContentType = [string] $_.content_type Digest = [string] $_.digest } }) $normalized.Add([pscustomobject] @{ ReleaseId = $release.id TagName = $tagName Name = [string] $release.name Body = [string] $release.body Draft = [bool] $release.draft Prerelease = [bool] $release.prerelease IsLatest = [bool] ($null -ne $latestReleaseId -and [long] $release.id -eq [long] $latestReleaseId) CreatedAt = $release.created_at PublishedAt = $release.published_at TargetCommitSha = [string] @($commitResult.Output)[0] Assets = $assets }) } $selectedAssetCount = if ($normalized.Count -eq 0) { 0 } else { [int] (($normalized | ForEach-Object { @($_.Assets).Count } | Measure-Object -Sum).Sum) } [pscustomobject] @{ PSTypeName = 'CopyGitHubRepo.ReleaseSelection' Repository = $Repository.FullName AvailableReleaseCount = $available.Count SelectedReleaseCount = $normalized.Count SelectedAssetCount = $selectedAssetCount SourceLatestReleaseId = $latestReleaseId SourceLatestTag = $latestReleaseTag SourceLatestSelected = [bool] ($normalized | Where-Object { $_.IsLatest } | Select-Object -First 1) IncludePatterns = @($ReleaseTag) ExcludePatterns = @($ReleaseExcludeTag) IncludePrerelease = [bool] $IncludePrerelease IncludeDraftReleases = [bool] $IncludeDraftReleases ReleaseCount = if ($PSBoundParameters.ContainsKey('ReleaseCount')) { $ReleaseCount } else { $null } Releases = $normalized.ToArray() } } |