Types/OpenPackage.Publisher/GitHubRelease.ps1
|
<# .SYNOPSIS Publishes Releases to GitHub .DESCRIPTION Publishes a Release to GitHub, if the version does not already exist. #> [CmdletBinding(SupportsShouldProcess,ConfirmImpact='High')] param( # The package [Parameter(Mandatory,ValueFromPipeline)] [IO.Packaging.Package] $Package, # One or more release asssets. These are files that are attached to the package. [string[]] $ReleaseAsset, # The GitHub Token used to publish the release. # If there is no GitHubEvent, this is presumed to be a Personal Access Token. [string] $GitHubToken = $env:GH_TOKEN, # The GitHubOwner. # If running in a workflow, this should be automatically detected. # If running outside of a workflow, this must be provided. [string] $GitHubOwner = $env:GITHUB_OWNER, # The GitHub Repository, in the form of `owner/repo` # If running in a workflow, this should be automatically detected. # If running outside of a workflow, this must be provided. [string] $GitHubRepository = $env:GITHUB_REPOSITORY ) # If there is no package version, throw if (-not $package.Version) { throw "No Package Version" } # If the package has no repository if (-not $package.RelationshipExists('repository')) { throw "Package not related to repository" # throw } # Get the git app (as opposed to any git functions) $gitApp = $ExecutionContext.SessionState.InvokeCommand.GetCommand('git', 'application') # If we could not get git if (-not $gitApp) { throw "No Git" # throw. } # Get the repository remote url $repositoryUrl = @(& $gitApp remote)[0] | ForEach-Object { & $gitApp remote get-url $_ } # and throw if we could not if (-not $repositoryUrl) { throw "No Repository" } # Make sure this package is related to the repository $packageGitRepo = $package.GetRelationship('repository').TargetUri if ($packageGitRepo -ne $repositoryUrl) { # and throw if that is not the case. throw "Package unrelated to '$repositoryUrl'" } # Get the github event $gitHubEvent = if ($env:GITHUB_EVENT_PATH) { [IO.File]::ReadAllText($env:GITHUB_EVENT_PATH) | ConvertFrom-Json } else { $null } # Warn about confirmation if we do not have one if (-not $gitHubEvent) { Write-Warning "No github event found, prompting for confirmation" } else { # If the event is not a merg, warn and return if (-not ($gitHubEvent.head_commit.message -match "Merge Pull Request #(?<PRNumber>\d+)") -and (-not $gitHubEvent.psobject.properties['inputs'])) { "::warning::Pull Request has not merged, skipping github release" | Out-Host return } } # Find the target version $targetVersion = "v$($package.Version)" # Go get all of our releases $releasesURL = "https://api.github.com/repos/$GitHubRepository/releases" # List out our source if we are running in a workflow. if ($gitHubEvent) { "Release URL: $releasesURL" | Out-Host } # Go get the releases. $listOfReleases = Invoke-RestMethod -Uri $releasesURL -Method Get -Headers @{ "Accept" = "application/vnd.github.v3+json" "Authorization" = if ($gitHubEvent) { "Bearer $GitHubToken" } elseif ($GitHubToken) { "Basic $( [System.Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$GitHubToken")) )" } } # and see if ours already exists $releaseExists = $listOfReleases | Where-Object tag_name -eq $targetVersion # If it does if ($releaseExists) { if ($gitHubEvent) { "::warning::Release '$($releaseExists.Name )' Already Exists" | Out-Host } else { Write-Warning "'$($releaseExists.Name )' Already Exists" } # store this to a variable so that we may potentially add assets. $releasedIt = $releaseExists } else { # If no release exists yet, # prepare our parameters $releaseParameters = [Ordered]@{ Uri = $releasesURL Method = 'POST' Body = [Ordered]@{ owner = "$gitHubOwner" repo = "$GitHubRepository" tag_name = $targetVersion name = "$($Package.Identifier) $($package.Version)" body = if ($env:RELEASENOTES) { $env:RELEASENOTES } elseif ($package.PowerShellManifest.PrivateData.PSData.ReleaseNotes) { $package.PowerShellManifest.PrivateData.PSData.ReleaseNotes } else { "$($package.Identifier) $targetVersion" } draft = if ($env:RELEASEISDRAFT) { [bool]::Parse($env:RELEASEISDRAFT) } else { $false } prerelease = if ($env:PRERELEASE) { [bool]::Parse($env:PRERELEASE) } else { $false } } } # If -WhatIf was passed, return the release parameters if ($whatIfPreference) { return $releaseParameters } # If there is no github event, prompt before releasing. if (-not $gitHubEvent -and -not $psCmdlet.ShouldProcess("Release $($releaseParameters.body.name)")) { return } # Create the release $releaseParameters.body = $releaseParameters.body | ConvertTo-Json -Depth 10 $ReleaseHeaders = @{ "Accept" = "application/vnd.github.v3+json" "Content-type" = "application/json" "Authorization" = if ($gitHubEvent) { "Bearer $GitHubToken" } else { "Basic $( [System.Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$GitHubToken")) )" } } $releasedIt = Invoke-RestMethod @releaseParameters -Headers $releaseHeaders } if (-not $releasedIt) { throw "Release failed" } else { $releasedIt | Out-Host } if ($ReleaseAsset) { $releaseUploadUrl = $releasedIt.upload_url -replace '\{.+$' $filesToRelease = Get-ChildItem -File -Path $ReleaseAsset -ErrorAction Ignore $releasedFiles = @{} foreach ($file in $filesToRelease) { if ($releasedFiles[$file.Name]) { Write-Warning "Already attached file $($file.Name)" continue } else { # If there is no github event, prompt before attaching. if (-not $gitHubEvent -and -not $psCmdlet.ShouldProcess("Attach $($file.name)")) { continue } $fileBytes = [IO.File]::ReadAllBytes($file.FullName) $releasedFiles[$file.Name] = Invoke-RestMethod -Uri "${releaseUploadUrl}?name=$($file.Name)" -Headers @{ "Accept" = "application/vnd.github+json" "Authorization" = if ($GitHubEvent) { "Bearer $GitHubToken" } else { "Basic $( [System.Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$GitHubToken")) )" } } -Body $fileBytes -ContentType Application/octet-stream $releasedFiles[$file.Name] } } if ($gitHubEvent) { "Attached $($releasedFiles.Count) file(s) to release" | Out-Host } } |