-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
4 changed files
with
287 additions
and
1 deletion.
There are no files selected for viewing
172 changes: 172 additions & 0 deletions
172
.github/actions/github-create-release/Create-GitHubRelease.ps1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
<# | ||
.SYNOPSIS | ||
Github Action script creating automated releases | ||
.DESCRIPTION | ||
The functionality is executed as an action on a github runner and creates automated releases for pull requests. | ||
#> | ||
|
||
if ([string]::IsNullOrEmpty($env:GH_TOKEN)) { | ||
throw "Error: GH_TOKEN environment variable is not set, see https://cli.github.com/manual/gh_auth_login for details" | ||
} | ||
|
||
if ([string]::IsNullOrEmpty($env:GH_CONTEXT)) { | ||
throw "Error: GH_CONTEXT environment variable is not set. Functionality is depending on github actions context variables." | ||
} | ||
|
||
$GithubRepository = $env:GH_CONTEXT | ConvertFrom-Json | Select-Object -ExpandProperty repository | ||
$PullRequstNumber = $env:GH_CONTEXT | ConvertFrom-Json | Select-Object -ExpandProperty event | Select-Object -ExpandProperty number | ||
|
||
<# | ||
.SYNOPSIS | ||
Class representing a Github Release using github CLI (gh) | ||
.DESCRIPTION | ||
Simple class mapping the output from a gh release list json response to a typed object | ||
#> | ||
class GithubRelease { | ||
[string]$name | ||
[string]$tagName | ||
[string]$publishedAt | ||
[bool]$isPrerelease | ||
[bool]$isLatest | ||
[bool]$isDraft | ||
[string]$notes | ||
[string[]]$files | ||
} | ||
|
||
<# | ||
.SYNOPSIS | ||
Creates a github release | ||
.DESCRIPTION | ||
Creates a github release. Makes sure to delete any prior releases with similar tag. | ||
#> | ||
function Create-GitHubRelease { | ||
param ( | ||
[Parameter(Mandatory)] | ||
[string]$TagName, | ||
[Parameter(Mandatory)] | ||
[string]$Title, | ||
[Parameter(Mandatory)] | ||
[string[]]$Files, | ||
[string]$PreRelease = "false", | ||
[string]$Draft = "false" | ||
) | ||
|
||
# Input parsing | ||
$isDraft = [bool]::Parse($Draft) | ||
$isPrerelease = [bool]::Parse($PreRelease) | ||
|
||
# Step 1: Get Previous Release | ||
[GithubRelease]$release = Invoke-GithubReleaseList -TagName $TagName | ||
|
||
# Step 2: Delete Previous Release | ||
$release | Invoke-GithubReleaseDelete | ||
|
||
# Step 3: Create new release | ||
$newrelease = [GithubRelease]@{ | ||
name = $Title | ||
tagName = $TagName | ||
isPrerelease = $isPrerelease | ||
isDraft = $isDraft | ||
notes = Get-ChangeNotes | ||
files = $Files | ||
} | ||
|
||
$newrelease | Invoke-GithubReleaseCreate | ||
} | ||
|
||
<# | ||
.SYNOPSIS | ||
Uses github CLI (gh) to retrieves a list of releases | ||
.DESCRIPTION | ||
Wrapping a "gh release list" call | ||
#> | ||
function Invoke-GithubReleaseList { | ||
param ( | ||
[string]$TagName | ||
) | ||
gh release list -L 10000 -R $GithubRepository --json "name,tagName,publishedAt,isPrerelease,isLatest,isDraft" ` | ||
| ConvertFrom-Json | ||
| Where-Object { $_.name -eq $TagName } | ||
} | ||
|
||
<# | ||
.SYNOPSIS | ||
Uses github CLI (gh) to delete a release | ||
.DESCRIPTION | ||
Wrapping a "gh release delete" call | ||
#> | ||
function Invoke-GithubReleaseDelete { | ||
[CmdletBinding()] | ||
param( | ||
[Parameter(ValueFromPipeline)] | ||
[GithubRelease]$release | ||
) | ||
|
||
if ($null -eq $release) { | ||
Write-Warning "No release to delete." | ||
return $release | ||
} | ||
|
||
Write-Host "Deleting $($release.Name)" | ||
gh release delete $release.Name -y --cleanup-tag -R $GithubRepository | ||
} | ||
|
||
<# | ||
.SYNOPSIS | ||
Uses github CLI (gh) to create a release | ||
.DESCRIPTION | ||
Wrapping a "gh release create" call | ||
#> | ||
function Invoke-GithubReleaseCreate { | ||
[CmdletBinding()] | ||
param( | ||
[Parameter(ValueFromPipeline)] | ||
[GithubRelease]$release | ||
) | ||
|
||
if ($null -eq $release) { | ||
Write-Warning "No release to create." | ||
return $release | ||
} | ||
|
||
Write-Verbose "Creating release: $($release.tagName)" | ||
|
||
$ArgNotes = if ($release.notes) { "-n `"$($release.notes)`"" } else { "--generate-notes" } | ||
$ArgPreRelease = if ($release.isPrerelease) { "--prerelease" } else { "" } | ||
$ArgDraft = if ($release.isDraft) { "--draft" } else { "" } | ||
|
||
$cmd = "gh release create $($release.tagName) -t $($release.name) -R $GithubRepository ${ArgPreRelease} ${ArgDraft} ${ArgNotes} $($release.Files)" | ||
Invoke-Expression $cmd | ||
} | ||
|
||
<# | ||
.SYNOPSIS | ||
Construct a change note | ||
.DESCRIPTION | ||
Creates changes notes for github release | ||
#> | ||
function Get-ChangeNotes { | ||
$commits = Invoke-GithubPrCommitHistory | ||
$notes = @("## Commits") | ||
$commits | ForEach-Object { $notes += "- $($_.sha.Substring(0,8)): $($_.commit.message) ($($_.committer.login))" } | ||
|
||
return $notes -join "`n" | ||
} | ||
|
||
<# | ||
.SYNOPSIS | ||
Uses github CLI (gh api) to retrieve commit history | ||
.DESCRIPTION | ||
Wrapping a "gh api /repos/{repo}/pulls/{pr_number}/commits" call | ||
#> | ||
function Invoke-GithubPrCommitHistory { | ||
gh api -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" "/repos/$GithubRepository/pulls/$PullRequstNumber/commits" | ConvertFrom-Json | ||
} |
66 changes: 66 additions & 0 deletions
66
.github/actions/github-create-release/Create-GithubRelease.Tests.ps1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
BeforeAll { | ||
$env:GH_TOKEN = "test" | ||
$env:GH_CONTEXT = @" | ||
{ | ||
"sha": "7fc6c8ad63a35313621bade00ddd2e91f756e093", | ||
"repository": "owner/reponame", | ||
"event": { | ||
"number": "1234" | ||
} | ||
} | ||
"@ | ||
. $PSScriptRoot/Create-GitHubRelease.ps1 | ||
} | ||
|
||
Describe "Create-GithubRelease" { | ||
|
||
Context "Invoke-GithubReleaseList" { | ||
It "Returns a release when release exist" -ForEach @( | ||
@{ Releases = @("v1"); TagName = "v1"; Expected = "v1" }, | ||
@{ Releases = @("v1", "v2"); TagName = "v1"; Expected = "v1" }, | ||
@{ Releases = @("not_v1"); TagName = "v1"; Expected = $null } | ||
) { | ||
## Mock gh release list | ||
Mock gh { | ||
$Releases | ForEach-Object { [GithubRelease]@{ Name = $_ } } | ConvertTo-Json -AsArray | ||
} | ||
$previousRelease = Invoke-GithubReleaseList -TagName $TagName | ||
$previousRelease.Name | Should -Be $Expected | ||
} | ||
} | ||
|
||
Context "Invoke-GithubReleaseDelete" { | ||
It "Deletes a piped release" -ForEach @( | ||
@{ Release = @{ Name = "noop" }; Expected = 1 }, | ||
@{ Release = $null; Expected = 0 } | ||
) { | ||
Mock gh {} | ||
Mock Invoke-GithubReleaseList { | ||
[GithubRelease] $Release | ||
} | ||
|
||
Invoke-GithubReleaseList | Invoke-GithubReleaseDelete | Should -Invoke -CommandName gh -Exactly -Times $Expected | ||
} | ||
} | ||
|
||
Context "Invoke-GithubReleaseCreate" { | ||
It "Should have <expected> as parameter" -ForEach @( | ||
@{ Release = @{ name = "xyz" }; Expected = "xyz" } | ||
@{ Release = @{ name = "xyz" }; Expected = "-t" } | ||
@{ Release = @{ tagName = "tagxyz" }; Expected = "tagxyz" } | ||
@{ Release = @{ notes = "" }; Expected = "--generate-notes" } | ||
@{ Release = @{ isPrerelease = $true }; Expected = "--prerelease" } | ||
@{ Release = @{ isDraft = $true }; Expected = "--draft" } | ||
@{ Release = @{ notes = "notes" }; Expected = "-n" } | ||
@{ Release = @{ notes = "notes" }; Expected = "notes" } | ||
) { | ||
Mock gh {} | ||
$rel = [GithubRelease]$Release | ||
$rel | Invoke-GithubReleaseCreate | ||
Should -Invoke -CommandName gh -Exactly 1 -ParameterFilter { | ||
$args -contains $Expected | ||
} | ||
} | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
name: Automatic Releases | ||
description: Automate the GitHub release process with assets, changelogs, pre-releases, and more | ||
branding: | ||
icon: package | ||
color: blue | ||
inputs: | ||
repo_token: | ||
description: GitHub secret token | ||
required: true | ||
automatic_release_tag: | ||
description: Git tag (for automatic releases) | ||
required: false | ||
draft: | ||
description: Should this release be marked as a draft? | ||
required: false | ||
default: false | ||
prerelease: | ||
description: Should this release be marked as a pre-release? | ||
required: false | ||
default: true | ||
title: | ||
description: Release title (for automatic releases) | ||
required: false | ||
files: | ||
description: Assets to upload to the release | ||
required: false | ||
outputs: | ||
automatic_releases_tag: | ||
description: The release tag this action just processed | ||
upload_url: | ||
description: The URL for uploading additional assets to the release | ||
runs: | ||
using: composite | ||
steps: | ||
- name: Create automatic release | ||
shell: pwsh | ||
env: | ||
GH_TOKEN: ${{ inputs.repo_token }} | ||
GH_CONTEXT: ${{ toJSON(github) }} | ||
run: | | ||
. ${{ github.action_path }}/Create-GitHubRelease.ps1 | ||
Create-GitHubRelease ` | ||
-TagName "${{ inputs.automatic_release_tag }}" ` | ||
-Draft "${{ inputs.draft }}" ` | ||
-PreRelease "${{ inputs.prerelease }}" ` | ||
-title "${{ inputs.title }}" ` | ||
-files "${{ inputs.files }}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters