-
Notifications
You must be signed in to change notification settings - Fork 0
344 lines (297 loc) · 13.6 KB
/
Copy pathrelease.yml
File metadata and controls
344 lines (297 loc) · 13.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
name: Publish Release
on:
push:
tags:
- "v*.*.*"
permissions:
contents: write
jobs:
build-windows:
name: Build Windows Release Asset
runs-on: windows-latest
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.11"
- name: Inject version from tag
shell: bash
run: |
VERSION="${GITHUB_REF_NAME#v}"
python scripts/inject_version.py "$VERSION"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install -r requirements.txt
- name: Build Windows app
run: |
pyinstaller --noconsole --onedir --noupx --name "OpenReader" --add-data "assets;assets" --icon ".\assets\branding\pdfreader_by_sparsh.ico" main.py
- name: Package Windows ZIP
run: |
Compress-Archive -Path "dist\OpenReader\*" -DestinationPath "OpenReader-Windows.zip"
- name: Build Inno Setup installer
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
$version = "$env:GITHUB_REF_NAME" -replace "^v", ""
Write-Host "=== Installing Inno Setup ==="
choco install innosetup --no-progress --limit-output -y 2>&1
if ($LASTEXITCODE -ne 0 -and $LASTEXITCODE -ne 1641 -and $LASTEXITCODE -ne 3010) {
throw "Chocolatey install failed with exit code $LASTEXITCODE"
}
refreshenv
Write-Host "=== Locating ISCC.exe ==="
$iscc = (Get-Command "iscc.exe" -ErrorAction SilentlyContinue).Source
if (-not $iscc) {
$paths = @(
"${env:ProgramFiles(x86)}\Inno Setup 6\ISCC.exe",
"${env:ProgramFiles}\Inno Setup 6\ISCC.exe",
"$env:LOCALAPPDATA\Programs\Inno Setup 6\ISCC.exe"
)
foreach ($p in $paths) { if (Test-Path $p) { $iscc = $p; break } }
}
if (-not $iscc) { throw "ISCC.exe not found" }
Write-Host "Using ISCC: $iscc"
Write-Host "=== Building installer via ISCC ==="
$srcDir = (Get-Item "dist\OpenReader").FullName
Write-Host "Source dir: $srcDir"
& $iscc /Q "/DAppVersion=$version" "/DAppSourceDir=$srcDir" installer/setup.iss
if ($LASTEXITCODE -ne 0) { throw "ISCC exited with code $LASTEXITCODE" }
$expected = "OpenReader-$version-Setup.exe"
if (Test-Path $expected) {
Copy-Item $expected "OpenReader-Setup.exe"
Write-Host "=== SUCCESS: OpenReader-Setup.exe built ==="
} else {
throw "Setup.exe not found at $expected"
}
- name: Build MSIX package
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
# Locate MakeAppx.exe
$makeAppx = Get-Command "MakeAppx.exe" -ErrorAction SilentlyContinue
if (-not $makeAppx) {
$sdkPaths = @(
"${env:ProgramFiles(x86)}\Windows Kits\10\bin\*\x64\MakeAppx.exe",
"${env:ProgramFiles}\Microsoft SDKs\ClickOnce\signtool\MakeAppx.exe"
)
foreach ($pattern in $sdkPaths) {
$found = Get-ChildItem $pattern -ErrorAction SilentlyContinue | Sort-Object -Descending | Select-Object -First 1
if ($found) { $makeAppx = $found; break }
}
}
if (-not $makeAppx) {
Write-Host "MakeAppx.exe not found — skipping MSIX build."
Write-Host "Install Windows SDK or Visual Studio Build Tools for MSIX support."
exit 0
}
# Normalize MakeAppx path
$makeAppxPath = if ($makeAppx -is [System.IO.FileInfo]) { $makeAppx.FullName } else { $makeAppx.Source }
Write-Host "MakeAppx: $makeAppxPath"
Write-Host "MakeAppx version: $(& $makeAppxPath --version 2>&1)"
$version = "$env:GITHUB_REF_NAME" -replace "^v", ""
# Map Git tag to MSIX 4-part version
$msixVersion = if ($version -match '^(\d+\.\d+\.\d+)-beta\.(\d+)$') {
"$($Matches[1]).$($Matches[2])"
} elseif ($version -match '^(\d+\.\d+\.\d+)$') {
"$($Matches[1]).0"
} else {
"$version.0"
}
Write-Host "MSIX version: $msixVersion"
$stageDir = "_msix_staging"
if (Test-Path $stageDir) { Remove-Item -Recurse -Force $stageDir }
New-Item -ItemType Directory -Path $stageDir -Force | Out-Null
# Copy app files
Write-Host "Copying app files to staging..."
Copy-Item -Path "dist\OpenReader\*" -Destination $stageDir -Recurse -Force
# Copy and patch manifest
# Use XML DOM patching (not regex) to avoid corrupting MinVersion/MaxVersionTested
Copy-Item -Path "packaging\msix\AppxManifest.xml" -Destination "$stageDir\AppxManifest.xml" -Force
$manifestPath = "$stageDir\AppxManifest.xml"
$manifestXml = New-Object System.Xml.XmlDocument
$manifestXml.PreserveWhitespace = $true
$manifestXml.Load($manifestPath)
$manifestXml.Package.Identity.Version = $msixVersion
$manifestXml.Save($manifestPath)
Write-Host "Manifest patched: Identity Version -> $msixVersion"
Write-Host ""
# Validate XML before MakeAppx
Write-Host "=== XML Validation ==="
try {
$xml = [xml](Get-Content $manifestPath -Raw)
Write-Host "XML parsed successfully."
Write-Host "Identity: $($xml.Package.Identity.Name)"
Write-Host "Version: $($xml.Package.Identity.Version)"
Write-Host "Publisher: $($xml.Package.Identity.Publisher)"
Write-Host "MinVersion: $($xml.Package.TargetDeviceFamily.MinVersion)"
Write-Host "MaxVersion: $($xml.Package.TargetDeviceFamily.MaxVersionTested)"
} catch {
Write-Host "XML PARSE ERROR: $_"
Write-Host "First 20 lines of manifest:"
Get-Content $manifestPath -TotalCount 20
Write-Host ""
Write-Host "First 200 bytes as hex:"
$bytes = [System.IO.File]::ReadAllBytes($manifestPath)
for ($i = 0; $i -lt [Math]::Min(200, $bytes.Length); $i++) {
Write-Host -NoNewline ("{0:X2} " -f $bytes[$i])
if (($i + 1) % 16 -eq 0) { Write-Host "" }
}
Write-Host ""
throw "Manifest XML validation failed: $_"
}
Write-Host ""
# Generate MSIX asset placeholders using Python
Write-Host "=== Generating MSIX asset placeholders ==="
$assetDir = "$stageDir\assets"
New-Item -ItemType Directory -Path $assetDir -Force | Out-Null
python tools/create_msix_placeholder_pngs.py $assetDir
if ($LASTEXITCODE -ne 0) { throw "Asset generation failed" }
Write-Host ""
# Validate all referenced assets exist in staging
Write-Host "=== Asset Validation ==="
$missingAssets = @()
$namespace = @{uap = "http://schemas.microsoft.com/appx/manifest/uap/windows10"}
$assetsToCheck = @($xml.Package.Logo)
$app = $xml.Package.Applications.Application
$assetsToCheck += $app."uap:VisualElements".Square150x150Logo
$assetsToCheck += $app."uap:VisualElements".Square44x44Logo
$assetsToCheck += $app."uap:VisualElements"."uap:DefaultTile".Wide310x150Logo
$assetsToCheck += $app."uap:VisualElements"."uap:DefaultTile".Square71x71Logo
$assetsToCheck += $app."uap:VisualElements"."uap:SplashScreen".Image
foreach ($asset in $assetsToCheck) {
$fullPath = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($stageDir, $asset))
if (-not (Test-Path $fullPath)) {
Write-Host "MISSING: $asset"
$missingAssets += $asset
} else {
Write-Host "FOUND: $asset"
}
}
if ($missingAssets.Count -gt 0) {
throw "Missing MSIX assets: $($missingAssets -join ', ')"
}
Write-Host "All assets validated."
# Build MSIX (unsigned)
$msixName = "OpenReader.msix"
Write-Host "Building MSIX..."
Write-Host "Command: $makeAppxPath pack /p $msixName /d $stageDir /l"
& $makeAppxPath pack /p $msixName /d $stageDir /l
if ($LASTEXITCODE -ne 0) {
Write-Host "MSIX BUILD FAILED. Diagnostics:"
Write-Host "Contents of _msix_staging:"
Get-ChildItem -Path $stageDir -Recurse | Select-Object Name, Length
throw "MakeAppx failed with exit code $LASTEXITCODE"
}
Write-Host "=== MSIX built: $msixName (unsigned) ==="
# Generate AppInstaller
# Use XML DOM patching to only update MainPackage version (not AppInstaller schema version)
$installerXml = New-Object System.Xml.XmlDocument
$installerXml.PreserveWhitespace = $true
$installerXml.Load("packaging\msix\AppInstaller.xml")
$nsm = New-Object System.Xml.XmlNamespaceManager($installerXml.NameTable)
$nsm.AddNamespace("ai", "http://schemas.microsoft.com/appx/appinstaller/2021")
$mainPkg = $installerXml.SelectSingleNode("//ai:MainPackage", $nsm)
if ($mainPkg) { $mainPkg.Version = $msixVersion }
$installerXml.Save("$pwd\OpenReader.appinstaller")
# Clean up
Remove-Item -Recurse -Force $stageDir
- name: Upload Windows release assets
uses: actions/upload-artifact@v7
with:
name: release-windows
path: |
OpenReader-Windows.zip
OpenReader-Setup.exe
OpenReader.msix
build-macos:
name: Build macOS Release Asset
strategy:
fail-fast: false
matrix:
include:
- runner: macos-15
asset-name: OpenReader-macOS-Apple-Silicon.zip
- runner: macos-15-intel
asset-name: OpenReader-macOS-Intel.zip
runs-on: ${{ matrix.runner }}
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.11"
- name: Inject version from tag
run: |
VERSION="${GITHUB_REF_NAME#v}"
python3 scripts/inject_version.py "$VERSION"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install -r requirements.txt
- name: Build macOS app
run: |
QT_QPA_PLATFORM=offscreen python tools/create_icon.py --source assets/branding/app-icon-source.png --macos-iconset assets/branding/AppIcon.iconset
iconutil -c icns assets/branding/AppIcon.iconset -o assets/branding/pdfreader_by_sparsh.icns
pyinstaller --windowed --onedir --noupx --name "OpenReader" --argv-emulation --icon "assets/branding/pdfreader_by_sparsh.icns" main.py
- name: Package macOS ZIP
run: |
ditto -c -k --sequesterRsrc --keepParent "dist/OpenReader.app" "${{ matrix.asset-name }}"
- name: Upload macOS release asset
uses: actions/upload-artifact@v7
with:
name: release-${{ matrix.asset-name }}
path: ${{ matrix.asset-name }}
publish:
name: Publish GitHub Release
runs-on: ubuntu-latest
needs:
- build-windows
- build-macos
steps:
- name: Download release assets
uses: actions/download-artifact@v8
with:
pattern: release-*
merge-multiple: true
path: release-assets
- name: Verify required assets exist
run: |
echo "=== Release assets ==="
ls -la release-assets/
test -f "release-assets/OpenReader-Windows.zip" || { echo "Missing Windows ZIP"; exit 1; }
test -f "release-assets/OpenReader-Setup.exe" || { echo "Missing Windows Setup.exe"; exit 1; }
test -f "release-assets/OpenReader-macOS-Apple-Silicon.zip" || { echo "Missing macOS Apple Silicon ZIP"; exit 1; }
test -f "release-assets/OpenReader-macOS-Intel.zip" || { echo "Missing macOS Intel ZIP"; exit 1; }
# MSIX is optional until signing is set up; warn if missing
if [ -f "release-assets/OpenReader.msix" ]; then
echo "MSIX package found — will attach to release"
else
echo "⚠️ MSIX package not found — MakeAppx.exe may not be available on this runner"
fi
echo "All required assets verified"
- name: Generate release notes
run: |
cat > /tmp/release-notes.md <<- NOTE_EOF
Release ${GITHUB_REF_NAME}.
## Assets
### Windows
- \`OpenReader.msix\` — MSIX package. May be unsigned — requires Windows Developer Mode for sideloading.
- \`OpenReader-Setup.exe\` — Legacy Inno Setup installer for manual recovery. Requires administrator rights.
- \`OpenReader-Windows.zip\` — Portable/manual recovery ZIP.
### macOS
- \`OpenReader-macOS-Apple-Silicon.zip\` — Experimental macOS Apple Silicon app bundle.
- \`OpenReader-macOS-Intel.zip\` — Experimental macOS Intel app bundle.
NOTE_EOF
- name: Publish release
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release create "$GITHUB_REF_NAME" release-assets/* \
--repo "$GITHUB_REPOSITORY" \
--verify-tag \
--title "OpenReader $GITHUB_REF_NAME" \
--notes-file /tmp/release-notes.md