Skip to content

Commit ea3f9db

Browse files
feat: OpenPackage.Publisher.GitHubRelease ( Fixes #207 )
1 parent 6c1bd05 commit ea3f9db

1 file changed

Lines changed: 224 additions & 0 deletions

File tree

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
<#
2+
.SYNOPSIS
3+
Publishes Releases to GitHub
4+
.DESCRIPTION
5+
Publishes a Release to GitHub, if the version does not already exist.
6+
#>
7+
[CmdletBinding(SupportsShouldProcess,ConfirmImpact='High')]
8+
param(
9+
# The package
10+
[Parameter(Mandatory,ValueFromPipeline)]
11+
[IO.Packaging.Package]
12+
$Package,
13+
14+
# One or more release asssets. These are files that are attached to the package.
15+
[string[]]
16+
$ReleaseAsset,
17+
18+
# The GitHub Token used to publish the release.
19+
# If there is no GitHubEvent, this is presumed to be a Personal Access Token.
20+
[string]
21+
$GitHubToken = $env:GH_TOKEN,
22+
23+
# The GitHubOwner.
24+
# If running in a workflow, this should be automatically detected.
25+
# If running outside of a workflow, this must be provided.
26+
[string]
27+
$GitHubOwner = $env:GITHUB_OWNER,
28+
29+
# The GitHub Repository, in the form of `owner/repo`
30+
# If running in a workflow, this should be automatically detected.
31+
# If running outside of a workflow, this must be provided.
32+
[string]
33+
$GitHubRepository = $env:GITHUB_REPOSITORY
34+
)
35+
36+
# If there is no package version, throw
37+
if (-not $package.Version) { throw "No Package Version" }
38+
39+
# If the package has no repository
40+
if (-not $package.RelationshipExists('repository')) {
41+
throw "Package not related to repository" # throw
42+
}
43+
44+
# Get the git app (as opposed to any git functions)
45+
$gitApp = $ExecutionContext.SessionState.InvokeCommand.GetCommand('git', 'application')
46+
# If we could not get git
47+
if (-not $gitApp) {
48+
throw "No Git" # throw.
49+
}
50+
51+
# Get the repository remote url
52+
$repositoryUrl = @(& $gitApp remote)[0] |
53+
ForEach-Object {
54+
& $gitApp remote get-url $_
55+
}
56+
57+
# and throw if we could not
58+
if (-not $repositoryUrl) {
59+
throw "No Repository"
60+
}
61+
62+
# Make sure this package is related to the repository
63+
$packageGitRepo = $package.GetRelationship('repository').TargetUri
64+
if ($packageGitRepo -ne $repositoryUrl) {
65+
# and throw if that is not the case.
66+
throw "Package unrelated to '$repositoryUrl'"
67+
}
68+
69+
70+
# Get the github event
71+
$gitHubEvent = if ($env:GITHUB_EVENT_PATH) {
72+
[IO.File]::ReadAllText($env:GITHUB_EVENT_PATH) | ConvertFrom-Json
73+
} else { $null }
74+
75+
# Warn about confirmation if we do not have one
76+
if (-not $gitHubEvent) {
77+
Write-Warning "No github event found, prompting for confirmation"
78+
} else {
79+
# If the event is not a merg, warn and return
80+
if (-not ($gitHubEvent.head_commit.message -match "Merge Pull Request #(?<PRNumber>\d+)") -and
81+
(-not $gitHubEvent.psobject.properties['inputs'])) {
82+
"::warning::Pull Request has not merged, skipping github release" | Out-Host
83+
return
84+
}
85+
}
86+
87+
# Find the target version
88+
$targetVersion = "v$($package.Version)"
89+
90+
# Go get all of our releases
91+
$releasesURL = "https://api.github.com/repos/$GitHubRepository/releases"
92+
93+
# List out our source if we are running in a workflow.
94+
if ($gitHubEvent) {
95+
"Release URL: $releasesURL" | Out-Host
96+
}
97+
98+
# Go get the releases.
99+
$listOfReleases =
100+
Invoke-RestMethod -Uri $releasesURL -Method Get -Headers @{
101+
"Accept" = "application/vnd.github.v3+json"
102+
"Authorization" =
103+
if ($gitHubEvent) {
104+
"Bearer $GitHubToken"
105+
} elseif ($GitHubToken) {
106+
"Basic $(
107+
[System.Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$GitHubToken"))
108+
)"
109+
}
110+
111+
}
112+
113+
# and see if ours already exists
114+
$releaseExists = $listOfReleases | Where-Object tag_name -eq $targetVersion
115+
116+
# If it does
117+
if ($releaseExists) {
118+
119+
if ($gitHubEvent) {
120+
"::warning::Release '$($releaseExists.Name )' Already Exists" | Out-Host
121+
} else {
122+
Write-Warning "'$($releaseExists.Name )' Already Exists"
123+
}
124+
125+
# store this to a variable so that we may potentially add assets.
126+
$releasedIt = $releaseExists
127+
} else {
128+
# If no release exists yet,
129+
# prepare our parameters
130+
$releaseParameters = [Ordered]@{
131+
Uri = $releasesURL
132+
Method = 'POST'
133+
Body = [Ordered]@{
134+
owner = "$gitHubOwner"
135+
repo = "$GitHubRepository"
136+
tag_name = $targetVersion
137+
name = "$($Package.Identifier) $($package.Version)"
138+
body =
139+
if ($env:RELEASENOTES) {
140+
$env:RELEASENOTES
141+
} elseif ($package.PowerShellManifest.PrivateData.PSData.ReleaseNotes) {
142+
$package.PowerShellManifest.PrivateData.PSData.ReleaseNotes
143+
} else {
144+
"$($package.Identifier) $targetVersion"
145+
}
146+
draft =
147+
if ($env:RELEASEISDRAFT) { [bool]::Parse($env:RELEASEISDRAFT) } else { $false }
148+
prerelease =
149+
if ($env:PRERELEASE) { [bool]::Parse($env:PRERELEASE) } else { $false }
150+
}
151+
}
152+
153+
# If -WhatIf was passed, return the release parameters
154+
if ($whatIfPreference) {
155+
return $releaseParameters
156+
}
157+
158+
# If there is no github event, prompt before releasing.
159+
if (-not $gitHubEvent -and -not $psCmdlet.ShouldProcess("Release $($releaseParameters.body.name)")) {
160+
return
161+
}
162+
163+
# Create the release
164+
$releaseParameters.body = $releaseParameters.body | ConvertTo-Json -Depth 10
165+
$ReleaseHeaders = @{
166+
"Accept" = "application/vnd.github.v3+json"
167+
"Content-type" = "application/json"
168+
"Authorization" = if ($gitHubEvent) {
169+
"Bearer $GitHubToken"
170+
} else {
171+
"Basic $(
172+
[System.Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$GitHubToken"))
173+
)"
174+
}
175+
}
176+
177+
$releasedIt = Invoke-RestMethod @releaseParameters -Headers $releaseHeaders
178+
}
179+
180+
if (-not $releasedIt) {
181+
throw "Release failed"
182+
} else {
183+
$releasedIt | Out-Host
184+
}
185+
186+
187+
188+
if ($ReleaseAsset) {
189+
$releaseUploadUrl = $releasedIt.upload_url -replace '\{.+$'
190+
191+
$filesToRelease =
192+
Get-ChildItem -File -Path $ReleaseAsset -ErrorAction Ignore
193+
194+
$releasedFiles = @{}
195+
foreach ($file in $filesToRelease) {
196+
if ($releasedFiles[$file.Name]) {
197+
Write-Warning "Already attached file $($file.Name)"
198+
continue
199+
}
200+
else {
201+
# If there is no github event, prompt before attaching.
202+
if (-not $gitHubEvent -and -not $psCmdlet.ShouldProcess("Attach $($file.name)")) {
203+
continue
204+
}
205+
$fileBytes = [IO.File]::ReadAllBytes($file.FullName)
206+
$releasedFiles[$file.Name] =
207+
Invoke-RestMethod -Uri "${releaseUploadUrl}?name=$($file.Name)" -Headers @{
208+
"Accept" = "application/vnd.github+json"
209+
"Authorization" = if ($GitHubEvent) {
210+
"Bearer $GitHubToken"
211+
} else {
212+
"Basic $(
213+
[System.Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$GitHubToken"))
214+
)"
215+
}
216+
} -Body $fileBytes -ContentType Application/octet-stream
217+
$releasedFiles[$file.Name]
218+
}
219+
}
220+
221+
if ($gitHubEvent) {
222+
"Attached $($releasedFiles.Count) file(s) to release" | Out-Host
223+
}
224+
}

0 commit comments

Comments
 (0)