feat: Let uloop launchers use project-pinned CLI versions#1413
Conversation
Give the long-lived dispatcher its own contract, assets, and publish workflow so regular CLI releases can ship only the project-local binary. Point setup/update/install flows at dispatcher releases, keep real CLI downloads on cli-v tags, and add guards/tests so dispatcher-facing changes require an intentional dispatcherVersion bump.
Parse dispatcher version JSON from the global uloop command and only allow dispatcher detections to satisfy path setup. Legacy pre-split CLIs can still surface their version for UI context, but no longer provide protocol compatibility that would block the required dispatcher update.
Start the dispatcher stream at 3.0.0 so pre-split 3.0.0-beta global binaries compare older and enter the self-update path. Also mirror the native CLI release tag integrity check in dispatcher publishing so uploaded assets cannot drift from the tag target.
Create and publish dispatcher *-beta.* tags with GitHub prerelease metadata so installer channel selection keeps distinguishing stable and beta releases.
Publish legacy uloop-* archives on CLI releases so existing beta dispatchers can reach the split dispatcher stream through their old self-update path.
|
Warning Review limit reached
More reviews will be available in 8 minutes and 8 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more credits in the billing tab to continue. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (15)
📝 WalkthroughWalkthroughThe PR separates dispatcher contract/version metadata from the CLI contract, switches editor and CLI flows to dispatcher-specific versions and tags, adds dispatcher version-bump and minimum-version guards, and introduces dispatcher publish, verification, and sync scripts. ChangesDispatcher release flow
Estimated code review effort🎯 5 (Critical) | ⏱️ ~90+ minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
5 issues found across 60 files
Note: This PR contains a large number of files. cubic only reviews up to 40 files per PR, so some files may not have been reviewed. cubic prioritizes the most important files to review.
On a pro plan you can use ultrareview for larger PRs.
Re-trigger cubic
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
cli/internal/cli/dispatcher_pin.go (1)
155-174: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winKeep the
CliConstants.csfallback compatible with older packages.This fallback path is what lets the dispatcher work with legacy project layouts that do not have a dispatcher pin yet. Requiring
MINIMUM_REQUIRED_DISPATCHER_VERSIONhere turns those projects into a hard error duringloadDispatcherPin, so the launcher can no longer start them at all. Please keep the new constant optional in this fallback path and deriveMinimumDispatcherVersionfrom the existing CLI minimum when it is absent.🩹 Suggested fix
dispatcherVersionMatch := dispatcherMinimumVersionPattern.FindStringSubmatch(text) - if len(dispatcherVersionMatch) != 2 { - return dispatcherPin{}, fmt.Errorf("%s does not define MINIMUM_REQUIRED_DISPATCHER_VERSION", constantsPath) - } - minimumDispatcherVersion := normalizeDispatcherVersion(dispatcherVersionMatch[1]) - if err := validateDispatcherCLIVersion(minimumDispatcherVersion); err != nil { - return dispatcherPin{}, fmt.Errorf("%s defines invalid MINIMUM_REQUIRED_DISPATCHER_VERSION: %w", constantsPath, err) + minimumDispatcherVersion := cliVersion + if len(dispatcherVersionMatch) == 2 { + minimumDispatcherVersion = normalizeDispatcherVersion(dispatcherVersionMatch[1]) + if err := validateDispatcherCLIVersion(minimumDispatcherVersion); err != nil { + return dispatcherPin{}, fmt.Errorf("%s defines invalid MINIMUM_REQUIRED_DISPATCHER_VERSION: %w", constantsPath, err) + } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cli/internal/cli/dispatcher_pin.go` around lines 155 - 174, The `loadDispatcherPin` fallback path in `dispatcher_pin.go` should stay compatible with legacy `CliConstants.cs` files that do not define `MINIMUM_REQUIRED_DISPATCHER_VERSION`. Update the parsing logic so this constant is optional in the fallback branch: if it is missing, derive `MinimumDispatcherVersion` from the existing CLI minimum instead of returning an error. Keep the validation for the new constant when present, and adjust the `dispatcherPin` construction so older packages still load successfully.
🧹 Nitpick comments (1)
.github/workflows/build-and-test.yml (1)
68-71: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low valueConsider passing
github.base_refviaenvinstead of inlining it inrun.zizmor flags template expansion of
${{ github.base_ref }}directly into the shell command. Whilebase_refis the upstream PR base branch (must already exist, so the practical risk is low and this mirrors the existing steps at Lines 54 and 61), moving it into anenvvar avoids the injection class entirely.🔒 Optional hardening
- name: Check dispatcher version bump if: github.event_name == 'pull_request' working-directory: cli - run: go run ./cmd/check-dispatcher-version-bump --base "origin/${{ github.base_ref }}" --head HEAD + env: + BASE_REF: origin/${{ github.base_ref }} + run: go run ./cmd/check-dispatcher-version-bump --base "$BASE_REF" --head HEAD🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/build-and-test.yml around lines 68 - 71, The dispatcher version bump step in the workflow is expanding github.base_ref directly inside the shell command, which should be avoided. Move github.base_ref into an env variable on the Check dispatcher version bump step, then reference that env var in the go run invocation for cmd/check-dispatcher-version-bump so the command no longer inlines the template expression.Source: Linters/SAST tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@Assets/Tests/Editor/CliInstallationDetectorTests.cs`:
- Around line 213-229: The CLI installation test is only asserting presence of
the protocol value and can miss dispatcher contract-generation mismatches.
Update the assertion in CliInstallationDetectorTests around
ParseShellCliInstallationOutput to verify the parsed DispatcherContractVersion
exactly, or compare it against a dispatcher-specific required contract constant
instead of CliConstants.REQUIRED_CLI_PROTOCOL_VERSION. Also add a negative test
case in the same CliInstallationDetector test area that fails when the
dispatcher contract version differs from the required generation.
In `@cli/internal/cli/run_help.go`:
- Around line 63-69: Update printLauncherHelp so the help text matches the new
split model: the description passed into printMainHelp should no longer say
"Native CLI" now that this entrypoint shows dispatcherVersion. Use a
launcher/dispatcher-oriented description that clearly distinguishes it from the
Unity tool CLI, and keep the change localized to printLauncherHelp and any
related help wording it feeds into printMainHelp.
In `@cli/internal/update/command.go`:
- Line 69: The target normalization path in the update command is preserving the
legacy CLI prefix, which causes dispatcher targets to be built with an extra cli
marker. Update the logic around DispatcherReleaseTag and NormalizeTargetVersion
so legacy inputs like cli-v3.0.0 are stripped to the base version before the
dispatcher tag is assembled, ensuring migrated commands resolve to
dispatcher-v3.0.0.
In `@Packages/src/Editor/Infrastructure/CLI/CliInstallationDetector.cs`:
- Around line 390-405: The ParseDispatcherContract method is ignoring the parsed
dispatcher protocol version and always returning
CliConstants.REQUIRED_CLI_PROTOCOL_VERSION, which hides mismatches. Update the
CliInstallationDetector.ParseDispatcherContract logic to use
dispatcherContractVersion after ReadProtocolVersion succeeds, and only return a
successful CliInstallationDetection when the parsed protocol matches the
required version; otherwise return the failure/null detection path. Keep the
existing null/empty checks on dispatcherVersion and dispatcherContractVersion,
but ensure the returned detection reflects the actual parsed protocol value
rather than a constant.
In `@Packages/src/Editor/Infrastructure/CLI/NativeCliInstaller.cs`:
- Around line 957-965: Update the release-tag normalization logic in
NativeCliInstaller.BuildReleaseTag so legacy cli-v... tags are rewritten to the
dispatcher prefix instead of being blindly prefixed. In the BuildReleaseTag
flow, keep the existing DispatcherReleaseTagPrefix passthrough, then add a
specific branch for the old CliConstants.RELEASE_TAG_PREFIX that replaces it
with CliConstants.DISPATCHER_RELEASE_TAG_PREFIX before the final bare-v
fallback. This ensures values like cli-v3.0.0 map to the correct dispatcher tag
rather than dispatcher-vcli-v3.0.0.
In `@scripts/verify-native-cli-release-assets.sh`:
- Around line 6-11: The advertised required asset set in the release
verification script is missing the legacy uloop bridge archives, even though the
completeness check still expects them. Update the EXPECTED_ASSETS list in
verify-native-cli-release-assets.sh to include the legacy uloop-* tar/zip
artifacts and their .sha256 files, or refactor the script to maintain separate
local and remote required asset lists while keeping the older-beta-launcher
bridge assets required by the readiness check.
---
Outside diff comments:
In `@cli/internal/cli/dispatcher_pin.go`:
- Around line 155-174: The `loadDispatcherPin` fallback path in
`dispatcher_pin.go` should stay compatible with legacy `CliConstants.cs` files
that do not define `MINIMUM_REQUIRED_DISPATCHER_VERSION`. Update the parsing
logic so this constant is optional in the fallback branch: if it is missing,
derive `MinimumDispatcherVersion` from the existing CLI minimum instead of
returning an error. Keep the validation for the new constant when present, and
adjust the `dispatcherPin` construction so older packages still load
successfully.
---
Nitpick comments:
In @.github/workflows/build-and-test.yml:
- Around line 68-71: The dispatcher version bump step in the workflow is
expanding github.base_ref directly inside the shell command, which should be
avoided. Move github.base_ref into an env variable on the Check dispatcher
version bump step, then reference that env var in the go run invocation for
cmd/check-dispatcher-version-bump so the command no longer inlines the template
expression.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 4c43d7bb-18a7-487e-a749-55e5e82ee620
⛔ Files ignored due to path filters (3)
scripts/check-release-installer.ps1is excluded by none and included by nonescripts/install.ps1is excluded by none and included by nonescripts/test-check-release-installer.ps1is excluded by none and included by none
📒 Files selected for processing (57)
.github/workflows/build-and-test.yml.github/workflows/dispatcher-publish.yml.github/workflows/native-cli-publish.yml.uloop/cli-pin.jsonAssets/Tests/Editor/CliInstallationDetectorTests.csAssets/Tests/Editor/CliSetupApplicationServiceTests.csAssets/Tests/Editor/NativeCliInstallerTests.csPackages/src/Editor/Application/CliSetupApplicationService.csPackages/src/Editor/Domain/CliConstants.csPackages/src/Editor/Infrastructure/CLI/CliInstallationDetector.csPackages/src/Editor/Infrastructure/CLI/NativeCliInstaller.csPackages/src/cli-pin.jsoncli/cmd/check-dispatcher-version-bump/main.gocli/contract.gocli/contract.jsoncli/contract_test.gocli/dispatcher-contract.jsoncli/internal/automation/dispatcher_minimum_version_guard.gocli/internal/automation/dispatcher_minimum_version_guard_test.gocli/internal/automation/dispatcher_version_bump_guard.gocli/internal/automation/dispatcher_version_bump_guard_test.gocli/internal/automation/protocol_minimum_version_guard.gocli/internal/automation/protocol_minimum_version_guard_test.gocli/internal/automation/release_pr_checks.gocli/internal/automation/release_pr_checks_test.gocli/internal/automation/release_pr_dispatcher_sync.gocli/internal/cli/dispatcher.gocli/internal/cli/dispatcher_download.gocli/internal/cli/dispatcher_pin.gocli/internal/cli/dispatcher_test.gocli/internal/cli/run.gocli/internal/cli/run_dispatch.gocli/internal/cli/run_help.gocli/internal/cli/tools.gocli/internal/cli/update.gocli/internal/cli/update_test.gocli/internal/update/command.gocli/internal/update/installer.gocli/internal/update/installer_test.gocli/protocol_version_consistency_test.goscripts/install.shscripts/package-dispatcher.shscripts/package-go-cli.shscripts/resolve-dispatcher-release-target.shscripts/resolve-native-cli-release-target.shscripts/sync-release-please-package-releases.shscripts/test-dispatcher-publish-workflow.shscripts/test-install-release-filter.shscripts/test-native-cli-publish-workflow.shscripts/test-release-please-config.shscripts/test-resolve-dispatcher-release-target.shscripts/test-resolve-native-cli-release-target.shscripts/test-sync-release-please-package-releases.shscripts/test-verify-dispatcher-release-assets.shscripts/test-verify-native-cli-release-assets.shscripts/verify-dispatcher-release-assets.shscripts/verify-native-cli-release-assets.sh
💤 Files with no reviewable changes (6)
- cli/internal/automation/release_pr_dispatcher_sync.go
- cli/contract.json
- scripts/resolve-native-cli-release-target.sh
- cli/internal/automation/release_pr_checks.go
- scripts/test-native-cli-publish-workflow.sh
- .github/workflows/native-cli-publish.yml
Prevent the split release tests from depending on CLI and dispatcher versions being different, and keep legacy CLI tag inputs from generating invalid dispatcher installer tags. - restore coverage for bridge archives that contain both dispatcher and real CLI binaries - document why setup reports dispatcher releases through existing CLI setup APIs
Tighten dispatcher contract compatibility checks, preserve failed release-asset list commands as not-ready states, and normalize migrated CLI release tags before dispatcher updates. - reject mismatched dispatcher contract generations during setup detection - fail dispatcher version guards on unexpected base read errors - clarify launcher help text for the split dispatcher model
Use the existing dispatcher release tag commit when a release already exists so asset-only follow-up publishes do not compare a stable tag against a later branch head. Also serialize dispatcher publish runs per branch and keep draft state under RUNNER_TEMP.
Summary
ulooplauncher can remain installed while each Unity project runs the CLI version pinned by that project.User Impact
Changes
Verification
scripts/check-go-cli.shscripts/package-go-cli.sh && scripts/verify-native-cli-release-assets.shscripts/package-dispatcher.sh && scripts/verify-dispatcher-release-assets.shscripts/test-resolve-dispatcher-release-target.sh && scripts/test-sync-release-please-package-releases.sh && scripts/test-dispatcher-publish-workflow.shscripts/test-resolve-native-cli-release-target.sh && scripts/test-native-cli-publish-workflow.sh/Users/a12115/dotfiles/.claude/skills/autoreview/scripts/autoreview --mode branch --base origin/v3-beta