Skip to content

Build Pipeline

github-actions[bot] edited this page May 8, 2026 · 7 revisions

Build Pipeline

build.ps1 orchestrates the build: version stamping, bundled-fallback fetch, .NET publish, and optional GitHub release packaging. Run from the repo root:

powershell -ExecutionPolicy Bypass -File build.ps1

Local builds produce dist/ only. Pass -Package when a zip and manifest are needed for GitHub release upload; those artifacts are written under dist/ by default. Pass -Version YYYY.M.D.N (release shape) or -Version YYYY.M.D.N-XXXX (dev shape, XXXX = 4 hex chars) to override the auto-derived stamp -- release.yml does this so the published tag, zip filename, and embedded assembly version stay in sync.

Phases

1. Git hooks activation (idempotent)

Sets git config core.hooksPath = .githooks if not already configured. Activates commit-msg, which rejects commit subjects with more than one (YYYY.M.D.N-XXXX) build-version stamp.

2. Version stamping

Format: YYYY.M.D.N-XXXX (dev) or YYYY.M.D.N (release).

  • YYYY.M.D is today
  • N is the daily build counter (read from .local_build_state.json)
  • XXXX is a fresh 4-hex UID

The numeric part (without the -XXXX suffix) goes into /p:Version= for dotnet publish, so the watchdog's FileVersionInfo can be read by the updater to determine "current version".

3. Bundled yt-dlp fallback fetch

Hits api.github.com/repos/yt-dlp/yt-dlp/releases/latest, downloads yt-dlp.exe to _tools_staging/yt-dlp-og-fallback.exe, and writes the version tag to _tools_staging/yt-dlp-og-fallback.version.txt. Skipped if the staged copy already matches the latest tag.

The fallback is what the watchdog drops back into VRChat's Tools dir as yt-dlp-og.exe if the user's backup goes missing -- it keeps the patched yt-dlp's server-down fallback path functional.

4. .NET publish

Six projects total: WKVRCProxy.Shared (DLL referenced by all four exes) + WKVRCProxy (watchdog) + WKVRCProxy.Updater + WKVRCProxy.Uninstaller + WKVRCProxy.YtDlp (patched wrapper) + WKVRCProxy.Tests. All target net10.0.

All four shipped exes use the AOT publish profile:

  • WKVRCProxy -> dist/WKVRCProxy.exe (~9 MB)
  • WKVRCProxy.Updater -> dist/WKVRCProxy.Updater.exe (~6 MB)
  • WKVRCProxy.Uninstaller -> dist/WKVRCProxy.Uninstaller.exe (~2 MB)
  • WKVRCProxy.YtDlp -> dist/tools/yt-dlp.exe (~3.27 MB)

<PublishAot>true</PublishAot> + <PublishTrimmed>true</PublishTrimmed> + <TrimMode>full</TrimMode> + <InvariantGlobalization>true</InvariantGlobalization>. JSON serialization goes through source-gen contexts (MeshJsonContext, MeshFallbackJsonContext, and WrapperJsonContext). Don't add reflection-based serializer, regex, or MessagePack paths; AOT builds must stay source-generated.

AOT prerequisites: Visual Studio Build Tools "Desktop development with C++" workload. The AOT publish step calls MSVC's link.exe. build.ps1 prepends the VS Installer dir (where vswhere.exe lives) to PATH so the AOT target can locate the toolchain. CI uses windows-latest which already has the workload installed; local devs need to install it once.

5. Tools staging in dist

  • dist/tools/yt-dlp-og-fallback.exe -- bundled vanilla yt-dlp (downloaded fresh from yt-dlp/yt-dlp releases each build)
  • dist/tools/yt-dlp-og-fallback.version.txt -- version tag of the bundled vanilla yt-dlp
  • dist/tools/yt-dlp.exe -- the patched yt-dlp wrapper (built FROM this repo -- WKVRCProxy.YtDlp with <AssemblyName>yt-dlp</AssemblyName> so the AOT publish lands the binary as yt-dlp.exe).

6. Optional package artifacts

Only runs when -Package is passed.

  • dist/WKVRCProxy-v<version>.zip containing the runnable contents of dist/.
  • dist/WKVRCProxy-v<version>.manifest.tsv with SHA256 + size for every file inside the zip.

Local builds do not create a repo-root release/ directory. GitHub releases are the only path that needs packaging artifacts.

CI pipeline

.github/workflows/ci.yml runs on push and PR to main:

  • Single windows-latest job
  • actions/setup-dotnet@v5 with 10.0.x
  • dotnet restore + dotnet build of WKVRCProxy.slnx in Release with -warnaserror

CI deliberately skips build.ps1 -- the smoke check is dotnet build. The actual release zip is produced by release.yml.

Release pipeline

.github/workflows/release.yml runs on tag push matching v*:

  • windows-latest, full build.ps1 -Version <stripped-tag> -Package
  • Promotes the ## Unreleased section in CHANGELOG.md and wiki/Changelog.md to the tagged version before the build.
  • gh release create $tag $zip --title $tag --notes "...SHA256: <hash>..." -- release notes carry the curated changelog excerpt plus an auto-generated commit list.
  • Opens a release/promote-changelog-<tag> PR with auto-merge so main eventually carries the promotion.

Tag format must match what build.ps1 accepts, with a leading v.

Changelog automation

CHANGELOG.md (and its wiki/ mirror) are autogenerated from commit subjects on main -- don't hand-edit either under ## Unreleased, edits will be overwritten on the next push.

  • .github/workflows/changelog-append.yml parses each commit on push as a conventional commit and appends bullets under ## Unreleased. feat: -> Added, fix: -> Fixed, perf:/refactor:/revert:/chore(deps): -> Changed; ! -> Breaking. docs:/build:/ci:/test:/non-deps chore: are skipped.
  • .github/workflows/release.yml renames ## Unreleased to ## [vTAG] - DATE before the build, then opens an auto-merge PR to push the promotion back to main.
  • Both workflows share a concurrency group so the appender can't race with a release-in-progress.

Overrides:

  • Skip a commit: include [skip changelog] in the subject.
  • Hand-edit a tagged section: edit either CHANGELOG.md or wiki/Changelog.md under the existing ## [vX] heading. Closed sections are not touched by the workflow; only ## Unreleased is automated.

Implementation lives in .github/scripts/Update-Changelog.ps1. Modes: Append, Promote, Notes.

Clone this wiki locally