This document describes the current production packaging and distribution contract for ThreadPilot releases.
- Windows 11 build machine (or GitHub Actions
windows-latest) - .NET SDK 8.x
- Optional for signing:
- Code-signing certificate (
.pfx) for Authenticode signing - Optional strong-name key (
.snk) if strong naming is required
The repository provides two publish profiles under Properties/PublishProfiles:
WinX64-SingleFile.pubxmlWinX64-ReadyToRun.pubxml
Shared packaging defaults are in Directory.Publish.props.
Release baseline requirements:
- Executable manifest must use requireAdministrator so portable and installed builds always launch elevated.
- Inno Setup compile warnings target: 0.
- Build and test stages must pass before packaging.
dotnet publish ThreadPilot.csproj -c Release -p:PublishProfile=WinX64-SingleFileOutput folder:
artifacts/release/singlefile/
iscc /DMyAppVersion=<version> /DMyAppSourceDir="..\\artifacts\\release\\singlefile" Installer/setup.issRecommended local command (prevents stale publish output by forcing a fresh publish before ISCC):
powershell -ExecutionPolicy Bypass -File build/build-installer.ps1 -Version <version>The installer now uses Inno Setup native dynamic theming (WizardStyle=modern dynamic windows11) and follows the current Windows light/dark preference at startup.
Optional override for QA/troubleshooting:
iscc /DMyWizardStyle="modern dark windows11" /DMyAppVersion=<version> /DMyAppSourceDir="..\\artifacts\\release\\singlefile" Installer/setup.issOutput folder:
artifacts/release/installer/
dotnet publish ThreadPilot.csproj -c Release -p:PublishProfile=WinX64-ReadyToRunOutput folder:
artifacts/release/readytorun/
- Generate key:
sn -k ThreadPilot.snk- Add to project settings:
<SignAssembly>true</SignAssembly><AssemblyOriginatorKeyFile>ThreadPilot.snk</AssemblyOriginatorKeyFile>
Sign binaries after publish:
signtool sign /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 /f path\to\cert.pfx /p <password> artifacts\release\singlefile\ThreadPilot.exe.github/workflows/release.yml supports optional signing with these repository secrets:
WINDOWS_SIGNING_CERT_BASE64: base64-encoded.pfxcertificateWINDOWS_SIGNING_CERT_PASSWORD: certificate password
Expose these values to the workflow as environment variables (same names) via repository/environment secrets.
When both secrets are present:
- The workflow decodes the certificate to the runner temp directory.
signtool.exesigns.exeartifacts before ZIP packaging.- SHA-256 checksums are generated for signed outputs.
When secrets are missing, the release still builds and publishes unsigned artifacts.
Use Inno Setup script (Installer/setup.iss) for primary end-user installer packaging.
iscc Installer/setup.issdotnet restoredotnet build ThreadPilot_1.sln --configuration Releasedotnet test Tests/ThreadPilot.Core.Tests/ThreadPilot.Core.Tests.csproj --configuration Release --collect:"XPlat Code Coverage" --settings "Tests/ThreadPilot.Core.Tests/coverlet.runsettings" --results-directory TestResults- Publish Single-file and ReadyToRun profiles
- Build Inno Setup installer from Single-file output
- Generate winget manifests from release metadata
- Sign artifacts
- Generate SHA-256 checksums
- Upload release artifacts
The release workflow currently publishes these GitHub release assets:
ThreadPilot_v<version>_Setup.exeThreadPilot_v<version>_singlefile_win-x64.zipThreadPilot_v<version>_readytorun_win-x64.zipSHA256SUMS.txt
Generated winget manifest YAML files and manifest.spdx.json are internal workflow artifacts only. They are retained for channel submission and release provenance, but they are not uploaded as public GitHub release assets.
Prefer the release page over hardcoded asset URLs:
https://github.com/PrimeBuild-pc/ThreadPilot/releases/latest
Use GitHub release as the source of truth for version alignment:
- Publish GitHub release
vX.Y.Zfirst. - Ensure winget/chocolatey metadata references the same
X.Y.Z. - Ensure package URLs point to assets under the same GitHub tag.
Channel behavior:
- Chocolatey packages can be temporarily hidden from normal search while moderation/verification is pending or failed.
- Winget packages are discoverable only after the manifest is accepted in microsoft/winget-pkgs and clients refresh sources.
Current workflow scope:
.github/workflows/release.ymlbuilds release artifacts, generates winget manifests from the version/tag/installer URL/SHA, and uploads those manifests as artifacts.- It automatically submits a PR to
microsoft/winget-pkgswhen release succeeds and winget secrets are configured. .github/workflows/publish-chocolatey.ymlvalidates Chocolatey packaging and can publish to the Chocolatey community feed, but it only runs through manualworkflow_dispatch.- Tagged public releases fail if winget publication secrets are missing; only manual
workflow_dispatchdry-runs may skip winget publication. - Chocolatey publication is intentionally decoupled from tagged public releases because older package versions can remain in Chocolatey moderation. Run it manually only after previous ThreadPilot versions clear moderation.
The release workflow no longer depends on a precommitted folder under winget/manifests/.../<version>.
Generate manifests locally with:
./build/generate-winget-manifests.ps1 `
-Version "1.1.3" `
-Tag "v1.1.3" `
-InstallerUrl "https://github.com/PrimeBuild-pc/ThreadPilot/releases/download/v1.1.3/ThreadPilot_v1.1.3_Setup.exe" `
-InstallerSha256 "<sha256>" `
-OutputRoot "winget-manifests"Expected output:
winget-manifests/PrimeBuild.ThreadPilot.yamlwinget-manifests/PrimeBuild.ThreadPilot.locale.en-US.yamlwinget-manifests/PrimeBuild.ThreadPilot.installer.yaml
Validation checklist:
- files exist
PackageIdentifierisPrimeBuild.ThreadPilotPackageVersionmatches the release version- installer URL and SHA are populated
Required repository secrets for full channel automation:
WINGET_GITHUB_TOKEN: PAT with permission to push to yourwinget-pkgsfork and create PRs.WINGET_FORK_OWNER: GitHub username/org that owns yourwinget-pkgsfork.CHOCOLATEY_API_KEY: API key forhttps://push.chocolatey.org/. Required only by the manual Chocolatey workflow whenpublish=true.
If winget secrets are missing on a tagged public release, the release workflow fails by policy instead of staying ambiguously green. Missing Chocolatey credentials do not block GitHub release creation.
Chocolatey publishing is manual. Use it after the GitHub release exists and after previous ThreadPilot package versions have cleared Chocolatey moderation.
Manual workflow:
- Open GitHub Actions.
- Select
Publish Chocolatey. - Run workflow with
tag=vX.Y.Z. - Use
publish=falseto validate/package only. - Use
publish=trueto push to Chocolatey, withCHOCOLATEY_API_KEYconfigured.
The workflow downloads ThreadPilot_vX.Y.Z_Setup.exe from the existing GitHub release, runs build/publish-chocolatey.ps1 in dry-run mode first, and uploads .nupkg, metadata JSON, and logs as workflow artifacts.
Local packaging-only validation:
./build/publish-chocolatey.ps1 `
-Version "1.1.3" `
-Tag "v1.1.3" `
-InstallerPath ".\artifacts\release\installer\ThreadPilot_v1.1.3_Setup.exe" `
-DryRun `
-PackageOutputDirectory ".\artifacts\choco-dryrun" `
-MetadataOutputPath ".\artifacts\choco-dryrun\chocolatey-package-metadata.json"Expected outputs:
threadpilot.<version>.nupkgchocolatey-package-metadata.json
The metadata JSON captures:
- resolved installer URL
- installer SHA256
- package path
- release notes URL
- whether publication was attempted
- dry-run / no-push result
Public publish path:
./build/publish-chocolatey.ps1 `
-Version "1.1.3" `
-Tag "v1.1.3" `
-InstallerPath ".\artifacts\release\installer\ThreadPilot_v1.1.3_Setup.exe" `
-ApiKey "<chocolatey-api-key>"Moderation note:
- A successful
choco pushmeans the package was submitted to Chocolatey. - It does not guarantee immediate discoverability in search results.
- Moderation delay is an external queue, not automatically evidence of a repo or workflow failure.
- Do not run the manual publish workflow for a new version while prior ThreadPilot versions are still blocked or pending in Chocolatey moderation.
Optional automation for publishing the GitHub release after artifacts are ready:
./build/create-github-release.ps1 -Version "<version>" -NotesFile "docs/release/RELEASE_NOTES.md"The release workflow (.github/workflows/release.yml) now builds:
- Inno Setup installer (
.exe) as primary installer artifact - Single-file package (ZIP)
- ReadyToRun package (ZIP)
- SHA-256 checksum manifest
- Optional signing of EXE artifacts when signing secrets are configured