Skip to content

Commit 7968f56

Browse files
derrodRytoEX
authored andcommitted
CI: Add Windows Patches Action
1 parent f7f06de commit 7968f56

File tree

7 files changed

+390
-0
lines changed

7 files changed

+390
-0
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
function Ensure-Location {
2+
<#
3+
.SYNOPSIS
4+
Ensures current location to be set to specified directory.
5+
.DESCRIPTION
6+
If specified directory exists, switch to it. Otherwise create it,
7+
then switch.
8+
.EXAMPLE
9+
Ensure-Location "My-Directory"
10+
Ensure-Location -Path "Path-To-My-Directory"
11+
#>
12+
13+
param(
14+
[Parameter(Mandatory)]
15+
[string] $Path
16+
)
17+
18+
if ( ! ( Test-Path $Path ) ) {
19+
$_Params = @{
20+
ItemType = "Directory"
21+
Path = ${Path}
22+
ErrorAction = "SilentlyContinue"
23+
}
24+
25+
New-Item @_Params | Set-Location
26+
} else {
27+
Set-Location -Path ${Path}
28+
}
29+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
function Invoke-External {
2+
<#
3+
.SYNOPSIS
4+
Invokes a non-PowerShell command.
5+
.DESCRIPTION
6+
Runs a non-PowerShell command, and captures its return code.
7+
Throws an exception if the command returns non-zero.
8+
.EXAMPLE
9+
Invoke-External 7z x $MyArchive
10+
#>
11+
12+
if ( $args.Count -eq 0 ) {
13+
throw 'Invoke-External called without arguments.'
14+
}
15+
16+
if ( ! ( Test-Path function:Log-Information ) ) {
17+
. $PSScriptRoot/Logger.ps1
18+
}
19+
20+
$Command = $args[0]
21+
$CommandArgs = @()
22+
23+
if ( $args.Count -gt 1) {
24+
$CommandArgs = $args[1..($args.Count - 1)]
25+
}
26+
27+
$_EAP = $ErrorActionPreference
28+
$ErrorActionPreference = "Continue"
29+
30+
Log-Debug "Invoke-External: ${Command} ${CommandArgs}"
31+
32+
& $command $commandArgs
33+
$Result = $LASTEXITCODE
34+
35+
$ErrorActionPreference = $_EAP
36+
37+
if ( $Result -ne 0 ) {
38+
throw "${Command} ${CommandArgs} exited with non-zero code ${Result}."
39+
}
40+
}
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
function Log-Debug {
2+
[CmdletBinding()]
3+
param(
4+
[Parameter(Mandatory,ValueFromPipeline)]
5+
[ValidateNotNullOrEmpty()]
6+
[string[]] $Message
7+
)
8+
9+
Process {
10+
foreach($m in $Message) {
11+
Write-Debug $m
12+
}
13+
}
14+
}
15+
16+
function Log-Verbose {
17+
[CmdletBinding()]
18+
param(
19+
[Parameter(Mandatory,ValueFromPipeline)]
20+
[ValidateNotNullOrEmpty()]
21+
[string[]] $Message
22+
)
23+
24+
Process {
25+
foreach($m in $Message) {
26+
Write-Verbose $m
27+
}
28+
}
29+
}
30+
31+
function Log-Warning {
32+
[CmdletBinding()]
33+
param(
34+
[Parameter(Mandatory,ValueFromPipeline)]
35+
[ValidateNotNullOrEmpty()]
36+
[string[]] $Message
37+
)
38+
39+
Process {
40+
foreach($m in $Message) {
41+
Write-Warning $m
42+
}
43+
}
44+
}
45+
46+
function Log-Error {
47+
[CmdletBinding()]
48+
param(
49+
[Parameter(Mandatory,ValueFromPipeline)]
50+
[ValidateNotNullOrEmpty()]
51+
[string[]] $Message
52+
)
53+
54+
Process {
55+
foreach($m in $Message) {
56+
Write-Error $m
57+
}
58+
}
59+
}
60+
61+
function Log-Information {
62+
[CmdletBinding()]
63+
param(
64+
[Parameter(Mandatory,ValueFromPipeline)]
65+
[ValidateNotNullOrEmpty()]
66+
[string[]] $Message
67+
)
68+
69+
Process {
70+
if ( ! ( $script:Quiet ) ) {
71+
$StageName = $( if ( $script:StageName -ne $null ) { $script:StageName } else { '' })
72+
$Icon = ' =>'
73+
74+
foreach($m in $Message) {
75+
Write-Host -NoNewLine -ForegroundColor Blue " ${StageName} $($Icon.PadRight(5)) "
76+
Write-Host "${m}"
77+
}
78+
}
79+
}
80+
}
81+
82+
function Log-Group {
83+
[CmdletBinding()]
84+
param(
85+
[Parameter(ValueFromPipeline)]
86+
[string[]] $Message
87+
)
88+
89+
Process {
90+
if ( $Env:CI -ne $null ) {
91+
if ( $script:LogGroup ) {
92+
Write-Output '::endgroup::'
93+
$script:LogGroup = $false
94+
}
95+
96+
if ( $Message.count -ge 1 ) {
97+
Write-Output "::group::$($Message -join ' ')"
98+
$script:LogGroup = $true
99+
}
100+
} else {
101+
if ( $Message.count -ge 1 ) {
102+
Log-Information $Message
103+
}
104+
}
105+
}
106+
}
107+
108+
function Log-Status {
109+
[CmdletBinding()]
110+
param(
111+
[Parameter(Mandatory,ValueFromPipeline)]
112+
[ValidateNotNullOrEmpty()]
113+
[string[]] $Message
114+
)
115+
116+
Process {
117+
if ( ! ( $script:Quiet ) ) {
118+
$StageName = $( if ( $StageName -ne $null ) { $StageName } else { '' })
119+
$Icon = ' >'
120+
121+
foreach($m in $Message) {
122+
Write-Host -NoNewLine -ForegroundColor Green " ${StageName} $($Icon.PadRight(5)) "
123+
Write-Host "${m}"
124+
}
125+
}
126+
}
127+
}
128+
129+
function Log-Output {
130+
[CmdletBinding()]
131+
param(
132+
[Parameter(Mandatory,ValueFromPipeline)]
133+
[ValidateNotNullOrEmpty()]
134+
[string[]] $Message
135+
)
136+
137+
Process {
138+
if ( ! ( $script:Quiet ) ) {
139+
$StageName = $( if ( $script:StageName -ne $null ) { $script:StageName } else { '' })
140+
$Icon = ''
141+
142+
foreach($m in $Message) {
143+
Write-Output " ${StageName} $($Icon.PadRight(5)) ${m}"
144+
}
145+
}
146+
}
147+
}
148+
149+
$Columns = (Get-Host).UI.RawUI.WindowSize.Width - 5
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
name: Run bouf Patch Generation
2+
description: Generates OBS updater manifest and patches
3+
inputs:
4+
gcsAccessKeyId:
5+
description: GCS S3 Access Key ID
6+
required: true
7+
gcsAccessKeySecret:
8+
description: GCS S3 Access Key Secret
9+
required: true
10+
workflowSecret:
11+
description: GitHub API token to use for API calls
12+
required: true
13+
tagName:
14+
description: GitHub Release tag
15+
required: true
16+
channel:
17+
description: Update channel
18+
required: false
19+
default: 'stable'
20+
21+
runs:
22+
using: composite
23+
steps:
24+
- uses: actions/checkout@v4
25+
with:
26+
path: "repo"
27+
fetch-depth: 0
28+
29+
- name: Download Release Artifact
30+
shell: pwsh
31+
env:
32+
GH_TOKEN: ${{ inputs.workflowSecret }}
33+
run: |
34+
# Download OBS release
35+
. ${env:GITHUB_ACTION_PATH}\Invoke-External.ps1
36+
Invoke-External gh release download "${{ inputs.tagName }}" -p "*-Windows.zip"
37+
Expand-Archive -Path "*-Windows.zip" -DestinationPath "${{ github.workspace }}/build"
38+
39+
- name: Setup bouf
40+
shell: pwsh
41+
env:
42+
BOUF_TAG: 'v0.6.3'
43+
BOUF_HASH: '7f1d266467620aa553a705391ee06128e8ee14af66129a0e64a282997fb6fd83'
44+
BOUF_NSIS_HASH: 'a234126de89f122b6a552df3416de3eabcb4195217626c7f4eaec71b20fe36eb'
45+
GH_TOKEN: ${{ github.token }}
46+
run: |
47+
# Download bouf release
48+
. ${env:GITHUB_ACTION_PATH}\Ensure-Location.ps1
49+
. ${env:GITHUB_ACTION_PATH}\Invoke-External.ps1
50+
Ensure-Location bouf
51+
$windows_zip = "bouf-windows-${env:BOUF_TAG}.zip"
52+
$nsis_zip = "bouf-nsis-${env:BOUF_TAG}.zip"
53+
Invoke-External gh release download "${env:BOUF_TAG}" -R "obsproject/bouf" -p $windows_zip -p $nsis_zip
54+
55+
if ((Get-FileHash $windows_zip -Algorithm SHA256).Hash -ne "${env:BOUF_HASH}") {
56+
throw "bouf hash does not match."
57+
}
58+
if ((Get-FileHash $nsis_zip -Algorithm SHA256).Hash -ne "${env:BOUF_NSIS_HASH}") {
59+
throw "NSIS package hash does not match."
60+
}
61+
62+
Expand-Archive -Path $windows_zip -DestinationPath bin
63+
Expand-Archive -Path $nsis_zip -DestinationPath nsis
64+
65+
- name: Install rclone and pandoc
66+
shell: pwsh
67+
run: |
68+
choco install rclone pandoc -y --no-progress
69+
70+
- name: Download Previous Builds
71+
shell: pwsh
72+
env:
73+
RCLONE_TRANSFERS: '100'
74+
RCLONE_FAST_LIST: 'true'
75+
RCLONE_EXCLUDE: '{pdbs/**,**/${{ inputs.tagName }}/**}'
76+
RCLONE_S3_PROVIDER: 'GCS'
77+
RCLONE_S3_ACCESS_KEY_ID: '${{ inputs.gcsAccessKeyId }}'
78+
RCLONE_S3_SECRET_ACCESS_KEY: '${{ inputs.gcsAccessKeySecret }}'
79+
RCLONE_S3_ENDPOINT: 'https://storage.googleapis.com'
80+
run: |
81+
rclone -q copy ":s3:obs-builds" "${{ github.workspace }}/old_builds"
82+
83+
- name: Prepare Release Notes
84+
shell: pwsh
85+
run: |
86+
# Release notes are just the tag body on Windows
87+
Set-Location repo
88+
git tag -l --format='%(contents:body)' ${{ inputs.version }} > "${{ github.workspace }}/notes.rst"
89+
90+
- name: Run bouf
91+
shell: pwsh
92+
run: |
93+
. ${env:GITHUB_ACTION_PATH}\Invoke-External.ps1
94+
$boufArgs = @(
95+
"--config", "${env:GITHUB_ACTION_PATH}/config.toml",
96+
"--version", "${{ inputs.tagName }}"
97+
"--branch", "${{ inputs.channel }}"
98+
"--notes-file", "${{ github.workspace }}/notes.rst"
99+
"-i", "${{ github.workspace }}/build"
100+
"-p", "${{ github.workspace }}/old_builds"
101+
"-o", "${{ github.workspace }}/output"
102+
"--updater-data-only"
103+
)
104+
Invoke-External "${{ github.workspace }}\bouf\bin\bouf.exe" @boufArgs
105+
106+
- name: Upload Outputs
107+
uses: actions/upload-artifact@v4
108+
with:
109+
name: windows-updater-files
110+
compression-level: 0
111+
path: ${{ github.workspace }}/output
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
[general]
2+
log_level = "trace"
3+
4+
[env]
5+
# On CI these should be in %PATH%
6+
sevenzip_path = "7z"
7+
makensis_path = "makensis"
8+
pandoc_path = "pandoc"
9+
pdbcopy_path = "C:/Program Files (x86)/Windows Kits/10/Debuggers/x64/pdbcopy.exe"
10+
11+
[prepare.codesign]
12+
skip_sign = true
13+
14+
[generate]
15+
patch_type = "zstd"
16+
compress_files = true
17+
18+
[package]
19+
20+
[package.installer]
21+
skip = true
22+
23+
[package.updater]
24+
vc_redist_path = "bouf/nsis/VC_redist.x64.exe"
25+
skip_sign = true

.github/workflows/dispatch.yaml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ on:
1212
- services
1313
- translations
1414
- documentation
15+
- patches
1516
ref:
1617
description: GitHub reference to use for job
1718
type: string
@@ -28,6 +29,10 @@ on:
2829
description: Custom macOS Intel build for Steam Upload
2930
type: string
3031
required: false
32+
channel:
33+
description: Channel to use when generating Windows update files
34+
type: string
35+
required: false
3136
permissions:
3237
contents: write
3338
jobs:
@@ -130,3 +135,17 @@ jobs:
130135
apiToken: ${{ secrets.CF_API_TOKEN }}
131136
accountId: ${{ secrets.CF_ACCOUNT_ID }}
132137
command: pages publish . --project-name=${{ vars.CF_PAGES_PROJECT }} --commit-hash='${{ steps.setup.outputs.commitHash }}'
138+
139+
windows-patches:
140+
name: Create Windows Patches 🩹
141+
if: github.repository_owner == 'obsproject' && inputs.job == 'patches'
142+
runs-on: windows-latest
143+
steps:
144+
- uses: actions/checkout@v4
145+
- uses: ./.github/actions/windows-patches
146+
with:
147+
tagName: ${{ inputs.ref }}
148+
workflowSecret: ${{ github.token }}
149+
channel: ${{ inputs.channel }}
150+
gcsAccessKeyId: ${{ secrets.GCS_ACCESS_KEY_ID }}
151+
gcsAccessKeySecret: ${{ secrets.GCS_ACCESS_KEY_SECRET }}

0 commit comments

Comments
 (0)