Skip to content

Commit 96c3530

Browse files
committed
Build portable single EXE release artifacts
1 parent 170ba1b commit 96c3530

1 file changed

Lines changed: 63 additions & 32 deletions

File tree

.github/workflows/release.yml

Lines changed: 63 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ permissions:
1111

1212
jobs:
1313
package:
14-
name: Package Windows artifacts
14+
name: Build portable Windows release
1515
runs-on: windows-latest
16-
timeout-minutes: 35
16+
timeout-minutes: 40
1717

1818
steps:
1919
- name: Checkout
@@ -33,43 +33,61 @@ jobs:
3333
- name: Protocol smoke validation
3434
run: dotnet run --project .\src\PtpLabClock.Console --configuration Release -- --validate-protocol --domain 0 --export-pcap .\TestResults\ptp-validation.pcap
3535

36-
- name: Publish WPF app - framework dependent
37-
run: dotnet publish .\src\PtpLabClock.App\PtpLabClock.App.csproj -c Release -r win-x64 --self-contained false -p:PublishSingleFile=true -p:PublishReadyToRun=false -o .\artifacts\PtpLabClock.App.win-x64.framework-dependent
36+
- name: Publish portable single EXE files
37+
shell: pwsh
38+
run: |
39+
$ErrorActionPreference = "Stop"
40+
$publishRoot = Resolve-Path "."
41+
New-Item -ItemType Directory -Path .\artifacts -Force | Out-Null
42+
New-Item -ItemType Directory -Path .\publish\app -Force | Out-Null
43+
New-Item -ItemType Directory -Path .\publish\console -Force | Out-Null
44+
45+
$singleFileProps = @(
46+
"-p:PublishSingleFile=true",
47+
"-p:SelfContained=true",
48+
"-p:IncludeNativeLibrariesForSelfExtract=true",
49+
"-p:EnableCompressionInSingleFile=true",
50+
"-p:PublishReadyToRun=false",
51+
"-p:PublishTrimmed=false",
52+
"-p:DebugType=None",
53+
"-p:DebugSymbols=false"
54+
)
3855
39-
- name: Publish WPF app - self contained
40-
run: dotnet publish .\src\PtpLabClock.App\PtpLabClock.App.csproj -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -p:EnableCompressionInSingleFile=true -p:PublishReadyToRun=false -o .\artifacts\PtpLabClock.App.win-x64.self-contained
56+
dotnet publish .\src\PtpLabClock.App\PtpLabClock.App.csproj -c Release -r win-x64 --self-contained true @singleFileProps -o .\publish\app
57+
dotnet publish .\src\PtpLabClock.Console\PtpLabClock.Console.csproj -c Release -r win-x64 --self-contained true @singleFileProps -o .\publish\console
4158
42-
- name: Publish console - self contained
43-
run: dotnet publish .\src\PtpLabClock.Console\PtpLabClock.Console.csproj -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -p:EnableCompressionInSingleFile=true -p:PublishReadyToRun=false -o .\artifacts\PtpLabClock.Console.win-x64.self-contained
59+
Copy-Item .\publish\app\PtpLabClock.App.exe .\artifacts\PtpLabClock.App.win-x64.portable.exe -Force
60+
Copy-Item .\publish\console\PtpLabClock.Console.exe .\artifacts\PtpLabClock.Console.win-x64.portable.exe -Force
4461
45-
- name: Add release notes to packages
46-
shell: pwsh
47-
run: |
48-
$packageDirs = Get-ChildItem .\artifacts -Directory
49-
foreach ($dir in $packageDirs) {
50-
Copy-Item .\LICENSE $dir.FullName -Force
51-
Copy-Item .\NOTICE $dir.FullName -Force
52-
Copy-Item .\THIRD-PARTY-NOTICES.md $dir.FullName -Force
53-
Copy-Item .\docs\release-readme.md (Join-Path $dir.FullName "README-FIRST.md") -Force
54-
}
62+
if (-not (Test-Path .\artifacts\PtpLabClock.App.win-x64.portable.exe)) { throw "App portable EXE was not created." }
63+
if (-not (Test-Path .\artifacts\PtpLabClock.Console.win-x64.portable.exe)) { throw "Console portable EXE was not created." }
5564
56-
- name: Create ZIP packages
65+
- name: Create optional ZIP packages with notices
5766
shell: pwsh
5867
run: |
59-
$zips = @(
60-
"PtpLabClock.App.win-x64.framework-dependent",
61-
"PtpLabClock.App.win-x64.self-contained",
62-
"PtpLabClock.Console.win-x64.self-contained"
68+
$ErrorActionPreference = "Stop"
69+
$packages = @(
70+
@{ Name = "PtpLabClock.App.win-x64.portable"; Exe = ".\artifacts\PtpLabClock.App.win-x64.portable.exe" },
71+
@{ Name = "PtpLabClock.Console.win-x64.portable"; Exe = ".\artifacts\PtpLabClock.Console.win-x64.portable.exe" }
6372
)
64-
foreach ($name in $zips) {
65-
Compress-Archive -Path ".\artifacts\$name\*" -DestinationPath ".\artifacts\$name.zip" -Force
73+
74+
foreach ($package in $packages) {
75+
$dir = Join-Path ".\artifacts" $package.Name
76+
New-Item -ItemType Directory -Path $dir -Force | Out-Null
77+
Copy-Item $package.Exe (Join-Path $dir (Split-Path $package.Exe -Leaf)) -Force
78+
Copy-Item .\LICENSE $dir -Force
79+
Copy-Item .\NOTICE $dir -Force
80+
Copy-Item .\THIRD-PARTY-NOTICES.md $dir -Force
81+
Copy-Item .\docs\release-readme.md (Join-Path $dir "README-FIRST.md") -Force
82+
Compress-Archive -Path (Join-Path $dir "*") -DestinationPath ".\artifacts\$($package.Name).zip" -Force
6683
}
6784
68-
- name: Generate checksums and release SBOM manifest
85+
- name: Generate checksums and SPDX-style release manifest
6986
shell: pwsh
7087
run: |
71-
$zipFiles = Get-ChildItem .\artifacts -Filter *.zip | Sort-Object Name
72-
$checksums = foreach ($file in $zipFiles) {
88+
$ErrorActionPreference = "Stop"
89+
$releaseFiles = Get-ChildItem .\artifacts -File | Where-Object { $_.Extension -in ".exe", ".zip" } | Sort-Object Name
90+
$checksums = foreach ($file in $releaseFiles) {
7391
$hash = Get-FileHash $file.FullName -Algorithm SHA256
7492
"$($hash.Hash.ToLowerInvariant()) $($file.Name)"
7593
}
@@ -79,7 +97,7 @@ jobs:
7997
spdxVersion = "SPDX-2.3"
8098
dataLicense = "CC0-1.0"
8199
SPDXID = "SPDXRef-DOCUMENT"
82-
name = "Process Bus Timing Lab release manifest"
100+
name = "Process Bus Timing Lab portable Windows release manifest"
83101
documentNamespace = "https://github.com/masarray/PtpLabClock/releases/$env:GITHUB_RUN_ID"
84102
creationInfo = [ordered]@{
85103
created = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
@@ -89,15 +107,16 @@ jobs:
89107
[ordered]@{ SPDXID = "SPDXRef-Package-PtpLabClock"; name = "PtpLabClock"; downloadLocation = "NOASSERTION"; filesAnalyzed = $false; licenseConcluded = "Apache-2.0"; licenseDeclared = "Apache-2.0"; copyrightText = "Copyright (C) 2026 Ari Sulistiono" },
90108
[ordered]@{ SPDXID = "SPDXRef-Package-SharpPcap"; name = "SharpPcap"; versionInfo = "6.3.1"; downloadLocation = "https://www.nuget.org/packages/SharpPcap/6.3.1"; filesAnalyzed = $false; licenseConcluded = "MIT"; licenseDeclared = "MIT"; copyrightText = "NOASSERTION" }
91109
)
92-
releaseArtifacts = @($zipFiles | ForEach-Object { [ordered]@{ name = $_.Name; sha256 = (Get-FileHash $_.FullName -Algorithm SHA256).Hash.ToLowerInvariant(); size = $_.Length } })
110+
releaseArtifacts = @($releaseFiles | ForEach-Object { [ordered]@{ name = $_.Name; sha256 = (Get-FileHash $_.FullName -Algorithm SHA256).Hash.ToLowerInvariant(); size = $_.Length } })
93111
}
94112
$sbom | ConvertTo-Json -Depth 8 | Set-Content .\artifacts\PtpLabClock.release-sbom.spdx.json -Encoding UTF8
95113
96-
- name: Upload artifacts
114+
- name: Upload release build artifact
97115
uses: actions/upload-artifact@v4
98116
with:
99-
name: release-packages
117+
name: portable-release-packages
100118
path: |
119+
.\artifacts\*.exe
101120
.\artifacts\*.zip
102121
.\artifacts\checksums.txt
103122
.\artifacts\PtpLabClock.release-sbom.spdx.json
@@ -108,8 +127,20 @@ jobs:
108127
uses: softprops/action-gh-release@v2
109128
with:
110129
files: |
130+
.\artifacts\*.exe
111131
.\artifacts\*.zip
112132
.\artifacts\checksums.txt
113133
.\artifacts\PtpLabClock.release-sbom.spdx.json
114134
.\TestResults\ptp-validation.pcap
115135
generate_release_notes: true
136+
body: |
137+
## Process Bus Timing Lab portable release
138+
139+
Download the direct portable EXE when you want the fastest Windows start:
140+
141+
- `PtpLabClock.App.win-x64.portable.exe` - WPF dashboard, self-contained single-file app.
142+
- `PtpLabClock.Console.win-x64.portable.exe` - CLI validation, RAW self-test, passive monitor, and scripts.
143+
144+
ZIP packages are also provided for users who want license notices and README files bundled beside the EXE.
145+
146+
RAW NIC mode requires Npcap and may require Administrator privileges. This software is a lab simulator and diagnostic companion, not a certified grandmaster or relay-acceptance timing reference.

0 commit comments

Comments
 (0)