From cf63b880042ca87a4490288774925d2c56e0dfa7 Mon Sep 17 00:00:00 2001 From: hatayama Date: Sun, 28 Jun 2026 10:01:03 +0900 Subject: [PATCH 1/3] Report dispatcher update version changes Show the dispatcher version transition after successful automatic self-updates and manual update commands so users can tell which launcher version will run next. --- cli/internal/cli/dispatcher.go | 60 +++++++++----- cli/internal/cli/dispatcher_test.go | 81 +++++++++++++++++++ cli/internal/cli/dispatcher_update_version.go | 81 +++++++++++++++++++ cli/internal/cli/update.go | 21 +++-- cli/internal/cli/update_test.go | 66 +++++++++++++++ 5 files changed, 279 insertions(+), 30 deletions(-) create mode 100644 cli/internal/cli/dispatcher_update_version.go diff --git a/cli/internal/cli/dispatcher.go b/cli/internal/cli/dispatcher.go index d8f265b63..b2e1aa287 100644 --- a/cli/internal/cli/dispatcher.go +++ b/cli/internal/cli/dispatcher.go @@ -18,20 +18,19 @@ import ( ) const ( - dispatcherCacheDirEnvName = "ULOOP_CACHE_DIR" - dispatcherDisableSelfUpdateEnvName = "ULOOP_DISABLE_SELF_UPDATE" - dispatcherCacheDirectoryName = "uloop" - dispatcherVersionsDirectoryName = "versions" - dispatcherUpdateStateFileName = "dispatcher-update.json" - dispatcherProjectPinRelativePath = ".uloop/cli-pin.json" - dispatcherPackagePinFileName = "cli-pin.json" - dispatcherUnityPackageName = "io.github.hatayama.uloopmcp" - dispatcherRealCLIUnixFileName = "uloop-cli" - dispatcherRealCLIWindowsFileName = "uloop-cli.exe" - dispatcherReleaseRepository = "hatayama/unity-cli-loop" - dispatcherReleaseBaseURL = "https://github.com/" + dispatcherReleaseRepository + "/releases/download" - dispatcherSelfUpdateInterval = 24 * time.Hour - dispatcherSelfUpdateRequiredRetryError = "Dispatcher update completed. Retry the command so the updated dispatcher can run." + dispatcherCacheDirEnvName = "ULOOP_CACHE_DIR" + dispatcherDisableSelfUpdateEnvName = "ULOOP_DISABLE_SELF_UPDATE" + dispatcherCacheDirectoryName = "uloop" + dispatcherVersionsDirectoryName = "versions" + dispatcherUpdateStateFileName = "dispatcher-update.json" + dispatcherProjectPinRelativePath = ".uloop/cli-pin.json" + dispatcherPackagePinFileName = "cli-pin.json" + dispatcherUnityPackageName = "io.github.hatayama.uloopmcp" + dispatcherRealCLIUnixFileName = "uloop-cli" + dispatcherRealCLIWindowsFileName = "uloop-cli.exe" + dispatcherReleaseRepository = "hatayama/unity-cli-loop" + dispatcherReleaseBaseURL = "https://github.com/" + dispatcherReleaseRepository + "/releases/download" + dispatcherSelfUpdateInterval = 24 * time.Hour ) var ( @@ -149,17 +148,12 @@ func enforceDispatcherFreshness(ctx context.Context, pin dispatcherPin, stderr i err := dispatcherRunUpdate(ctx) if err == nil { markDispatcherSelfUpdateChecked() + updatedVersion := dispatcherInstalledVersionOrEmpty(ctx) if updateRequired { - writeErrorEnvelope(stderr, cliError{ - ErrorCode: errorCodeCLIUpdateRequired, - Phase: errorPhaseExecution, - Message: dispatcherSelfUpdateRequiredRetryError, - Retryable: true, - SafeToRetry: true, - NextActions: []string{"Retry the same uloop command."}, - }) + writeDispatcherSelfUpdateRequiredError(stderr, updatedVersion) return true, 1 } + writeOptionalDispatcherUpdateCompletion(stderr, dispatcherVersion, updatedVersion) return false, 0 } @@ -172,6 +166,28 @@ func enforceDispatcherFreshness(ctx context.Context, pin dispatcherPin, stderr i return false, 0 } +func writeDispatcherSelfUpdateRequiredError(stderr io.Writer, updatedVersion string) { + message := "Dispatcher update completed. Retry the command so the updated dispatcher can run." + if dispatcherVersionChanged(dispatcherVersion, updatedVersion) { + message = "Dispatcher updated from " + dispatcherVersion + " to " + updatedVersion + ". Retry the command so the updated dispatcher can run." + } + details := map[string]any{ + "CurrentDispatcherVersion": dispatcherVersion, + } + if updatedVersion != "" { + details["UpdatedDispatcherVersion"] = updatedVersion + } + writeErrorEnvelope(stderr, cliError{ + ErrorCode: errorCodeCLIUpdateRequired, + Phase: errorPhaseExecution, + Message: message, + Retryable: true, + SafeToRetry: true, + NextActions: []string{"Retry the same uloop command."}, + Details: details, + }) +} + func writeDispatcherManualUpdateRequiredError(stderr io.Writer, minimumVersion string, reason string) { writeErrorEnvelope(stderr, cliError{ ErrorCode: errorCodeCLIUpdateRequired, diff --git a/cli/internal/cli/dispatcher_test.go b/cli/internal/cli/dispatcher_test.go index 23c60dc76..40374fb04 100644 --- a/cli/internal/cli/dispatcher_test.go +++ b/cli/internal/cli/dispatcher_test.go @@ -231,6 +231,87 @@ func TestEnforceDispatcherFreshnessDoesNotMarkFailedOptionalUpdateChecked(t *tes } } +func TestEnforceDispatcherFreshnessReportsOptionalUpdateVersionChange(t *testing.T) { + // Verifies optional dispatcher self-updates tell users which launcher version will run next. + t.Setenv(dispatcherCacheDirEnvName, t.TempDir()) + restoreDispatcherUpdateHooks := stubDispatcherUpdateHooks(t, "9.9.9") + defer restoreDispatcherUpdateHooks() + + var stderr bytes.Buffer + handled, code := enforceDispatcherFreshness( + context.Background(), + dispatcherPin{MinimumDispatcherVersion: dispatcherVersion}, + &stderr) + + if handled || code != 0 { + t.Fatalf("freshness result mismatch: handled=%t code=%d", handled, code) + } + expected := "uloop: dispatcher updated from " + dispatcherVersion + " to 9.9.9" + if !bytes.Contains(stderr.Bytes(), []byte(expected)) { + t.Fatalf("freshness output mismatch: %s", stderr.String()) + } +} + +func TestEnforceDispatcherFreshnessSkipsOptionalUpdateMessageWhenVersionDidNotChange(t *testing.T) { + // Verifies no-op optional dispatcher self-updates do not add noise before the real command output. + t.Setenv(dispatcherCacheDirEnvName, t.TempDir()) + restoreDispatcherUpdateHooks := stubDispatcherUpdateHooks(t, dispatcherVersion) + defer restoreDispatcherUpdateHooks() + + var stderr bytes.Buffer + handled, code := enforceDispatcherFreshness( + context.Background(), + dispatcherPin{MinimumDispatcherVersion: dispatcherVersion}, + &stderr) + + if handled || code != 0 { + t.Fatalf("freshness result mismatch: handled=%t code=%d", handled, code) + } + if stderr.Len() != 0 { + t.Fatalf("expected no optional update output, got: %s", stderr.String()) + } +} + +func TestEnforceDispatcherFreshnessReportsRequiredUpdateVersionChange(t *testing.T) { + // Verifies required dispatcher self-updates include the version change before asking for a retry. + t.Setenv(dispatcherCacheDirEnvName, t.TempDir()) + restoreDispatcherUpdateHooks := stubDispatcherUpdateHooks(t, "999.0.0") + defer restoreDispatcherUpdateHooks() + + var stderr bytes.Buffer + handled, code := enforceDispatcherFreshness( + context.Background(), + dispatcherPin{MinimumDispatcherVersion: "999.0.0"}, + &stderr) + + if !handled || code != 1 { + t.Fatalf("freshness result mismatch: handled=%t code=%d", handled, code) + } + expected := "Dispatcher updated from " + dispatcherVersion + " to 999.0.0" + if !bytes.Contains(stderr.Bytes(), []byte(expected)) { + t.Fatalf("freshness output mismatch: %s", stderr.String()) + } + if !bytes.Contains(stderr.Bytes(), []byte("Retry the command")) { + t.Fatalf("retry guidance missing: %s", stderr.String()) + } +} + +func stubDispatcherUpdateHooks(t *testing.T, updatedVersion string) func() { + t.Helper() + previousRunner := dispatcherRunUpdate + previousReader := dispatcherReadInstalledVersion + dispatcherRunUpdate = func(context.Context) error { + return nil + } + dispatcherReadInstalledVersion = func(context.Context) (string, error) { + return updatedVersion, nil + } + return func() { + dispatcherRunUpdate = previousRunner + dispatcherReadInstalledVersion = previousReader + } +} + func TestExtractDispatcherRealCLIFromTarPrefersRealCLI(t *testing.T) { // Verifies legacy bridge archives that contain dispatcher first still extract the real CLI binary. tempDir := t.TempDir() diff --git a/cli/internal/cli/dispatcher_update_version.go b/cli/internal/cli/dispatcher_update_version.go new file mode 100644 index 000000000..68de26b6c --- /dev/null +++ b/cli/internal/cli/dispatcher_update_version.go @@ -0,0 +1,81 @@ +package cli + +import ( + "context" + "encoding/json" + "errors" + "io" + "os" + "os/exec" + "strings" +) + +var dispatcherReadInstalledVersion = readInstalledDispatcherVersion + +type dispatcherVersionPayload struct { + DispatcherVersion string +} + +func readInstalledDispatcherVersion(ctx context.Context) (string, error) { + executablePath, err := os.Executable() + if err != nil { + return "", err + } + + command := exec.CommandContext(ctx, executablePath, "--version", "--json") + output, err := command.Output() + if err != nil { + return "", err + } + + payload := dispatcherVersionPayload{} + if err := json.Unmarshal(output, &payload); err != nil { + return "", err + } + + updatedVersion := normalizeDispatcherVersion(payload.DispatcherVersion) + if updatedVersion == "" { + return "", errors.New("updated dispatcher version is empty") + } + if err := validateDispatcherCLIVersion(updatedVersion); err != nil { + return "", err + } + return updatedVersion, nil +} + +func dispatcherInstalledVersionOrEmpty(ctx context.Context) string { + updatedVersion, err := dispatcherReadInstalledVersion(ctx) + if err != nil { + return "" + } + return updatedVersion +} + +func dispatcherVersionChanged(fromVersion string, toVersion string) bool { + fromVersion = strings.TrimSpace(fromVersion) + toVersion = strings.TrimSpace(toVersion) + return fromVersion != "" && toVersion != "" && fromVersion != toVersion +} + +func writeOptionalDispatcherUpdateCompletion(stderr io.Writer, fromVersion string, toVersion string) { + if !dispatcherVersionChanged(fromVersion, toVersion) { + return + } + writeFormat( + stderr, + "uloop: dispatcher updated from %s to %s. Future uloop commands will use the updated launcher.\n", + fromVersion, + toVersion) +} + +func writeManualDispatcherUpdateCompletion(stdout io.Writer, fromVersion string, toVersion string) { + if toVersion == "" { + writeLine(stdout, "uloop launcher update completed.") + return + } + if !dispatcherVersionChanged(fromVersion, toVersion) { + writeLine(stdout, "uloop launcher is already up to date at "+toVersion+".") + return + } + writeLine(stdout, "uloop launcher updated from "+fromVersion+" to "+toVersion+".") +} diff --git a/cli/internal/cli/update.go b/cli/internal/cli/update.go index bd38060d9..1daeaf48e 100644 --- a/cli/internal/cli/update.go +++ b/cli/internal/cli/update.go @@ -6,7 +6,6 @@ import ( "os/exec" "runtime" - clicontract "github.com/hatayama/unity-cli-loop/cli" "github.com/hatayama/unity-cli-loop/cli/internal/update" ) @@ -16,6 +15,8 @@ const ( updateToVersionFlagName = "to-version" ) +var updateRunCommand = runUpdateCommand + type updateOptions struct { targetVersion string } @@ -35,7 +36,7 @@ func tryHandleUpdateRequest(ctx context.Context, args []string, stdout io.Writer } updateCommand, err := update.CommandForOS(runtime.GOOS, update.Options{ - CurrentVersion: clicontract.DispatcherCurrent.DispatcherVersion, + CurrentVersion: dispatcherVersion, TargetVersion: options.targetVersion, }) if err != nil { @@ -44,10 +45,7 @@ func tryHandleUpdateRequest(ctx context.Context, args []string, stdout io.Writer } writeLine(stdout, "Updating global uloop launcher...") - command := exec.CommandContext(ctx, updateCommand.Name, updateCommand.Args...) - command.Stdout = stdout - command.Stderr = stderr - if err := command.Run(); err != nil { + if err := updateRunCommand(ctx, updateCommand, stdout, stderr); err != nil { writeErrorEnvelope(stderr, cliError{ ErrorCode: errorCodeInternalError, Phase: errorPhaseExecution, @@ -62,7 +60,7 @@ func tryHandleUpdateRequest(ctx context.Context, args []string, stdout io.Writer }) return true, 1 } - writeLine(stdout, "uloop launcher update completed.") + writeManualDispatcherUpdateCompletion(stdout, dispatcherVersion, dispatcherInstalledVersionOrEmpty(ctx)) return true, 0 } @@ -72,7 +70,7 @@ func updateCommandForOS(goos string) (string, []string, error) { func updateCommandForOSWithOptions(goos string, options updateOptions) (string, []string, error) { command, err := update.CommandForOS(goos, update.Options{ - CurrentVersion: clicontract.DispatcherCurrent.DispatcherVersion, + CurrentVersion: dispatcherVersion, TargetVersion: options.targetVersion, }) if err != nil { @@ -81,6 +79,13 @@ func updateCommandForOSWithOptions(goos string, options updateOptions) (string, return command.Name, command.Args, nil } +func runUpdateCommand(ctx context.Context, updateCommand update.Command, stdout io.Writer, stderr io.Writer) error { + command := exec.CommandContext(ctx, updateCommand.Name, updateCommand.Args...) + command.Stdout = stdout + command.Stderr = stderr + return command.Run() +} + func printUpdateHelp(stdout io.Writer) { writeLine(stdout, "Usage:") writeLine(stdout, " uloop update [--to-version ]") diff --git a/cli/internal/cli/update_test.go b/cli/internal/cli/update_test.go index 40d0eca23..685492692 100644 --- a/cli/internal/cli/update_test.go +++ b/cli/internal/cli/update_test.go @@ -1,6 +1,10 @@ package cli import ( + "bytes" + "context" + "io" + "runtime" "strings" "testing" @@ -187,6 +191,44 @@ func TestParseUpdateOptionsRejectsInvalidVersion(t *testing.T) { } } +func TestTryHandleUpdateRequestReportsVersionChange(t *testing.T) { + // Verifies manual dispatcher updates tell users which launcher version was installed. + skipWhenNativeUpdateIsUnsupported(t) + restoreUpdateHooks := stubManualUpdateHooks(t, "9.9.9") + defer restoreUpdateHooks() + + var stdout bytes.Buffer + var stderr bytes.Buffer + handled, code := tryHandleUpdateRequest(context.Background(), []string{updateCommandName}, &stdout, &stderr) + + if !handled || code != 0 { + t.Fatalf("update result mismatch: handled=%t code=%d stderr=%s", handled, code, stderr.String()) + } + expected := "uloop launcher updated from " + dispatcherVersion + " to 9.9.9." + if !bytes.Contains(stdout.Bytes(), []byte(expected)) { + t.Fatalf("update output mismatch: %s", stdout.String()) + } +} + +func TestTryHandleUpdateRequestReportsAlreadyCurrentVersion(t *testing.T) { + // Verifies manual dispatcher updates explain when the selected release matches the installed launcher. + skipWhenNativeUpdateIsUnsupported(t) + restoreUpdateHooks := stubManualUpdateHooks(t, dispatcherVersion) + defer restoreUpdateHooks() + + var stdout bytes.Buffer + var stderr bytes.Buffer + handled, code := tryHandleUpdateRequest(context.Background(), []string{updateCommandName}, &stdout, &stderr) + + if !handled || code != 0 { + t.Fatalf("update result mismatch: handled=%t code=%d stderr=%s", handled, code, stderr.String()) + } + expected := "uloop launcher is already up to date at " + dispatcherVersion + "." + if !bytes.Contains(stdout.Bytes(), []byte(expected)) { + t.Fatalf("update output mismatch: %s", stdout.String()) + } +} + func TestUpdateCommandForLinuxIsUnsupported(t *testing.T) { // Verifies Linux update fails before trying to run a platform-specific update. _, _, err := updateCommandForOS("linux") @@ -205,3 +247,27 @@ func TestUpdateCommandRejectsUnsupportedOS(t *testing.T) { t.Fatal("expected unsupported OS error") } } + +func skipWhenNativeUpdateIsUnsupported(t *testing.T) { + t.Helper() + if runtime.GOOS == "darwin" || runtime.GOOS == "windows" { + return + } + t.Skip("native update is supported only on macOS and Windows") +} + +func stubManualUpdateHooks(t *testing.T, updatedVersion string) func() { + t.Helper() + previousRunner := updateRunCommand + previousReader := dispatcherReadInstalledVersion + updateRunCommand = func(context.Context, update.Command, io.Writer, io.Writer) error { + return nil + } + dispatcherReadInstalledVersion = func(context.Context) (string, error) { + return updatedVersion, nil + } + return func() { + updateRunCommand = previousRunner + dispatcherReadInstalledVersion = previousReader + } +} From 7726af0ccb25bd11a296198950cbce1a3a4f6f61 Mon Sep 17 00:00:00 2001 From: hatayama Date: Sun, 28 Jun 2026 10:15:14 +0900 Subject: [PATCH 2/3] Bump dispatcher release version Advance the dispatcher contract version marker so the changed dispatcher launcher code can produce a new dispatcher release. --- cli/dispatcher-contract.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/dispatcher-contract.json b/cli/dispatcher-contract.json index dd0144087..ce80274ef 100644 --- a/cli/dispatcher-contract.json +++ b/cli/dispatcher-contract.json @@ -1,5 +1,5 @@ { "schemaVersion": 1, - "dispatcherVersion": "3.0.1-beta.2", + "dispatcherVersion": "3.0.1-beta.3", "dispatcherContractVersion": 1 } From a1baa08206d3ba7deee35e6539df12f6779344e0 Mon Sep 17 00:00:00 2001 From: hatayama Date: Sun, 28 Jun 2026 10:23:17 +0900 Subject: [PATCH 3/3] Tighten dispatcher update version reporting Normalize dispatcher update versions before comparison and reporting, and assert manual update success paths keep status output off stderr. --- cli/internal/cli/dispatcher.go | 11 ++++---- cli/internal/cli/dispatcher_update_version.go | 27 ++++++++++++------- .../cli/dispatcher_update_version_test.go | 25 +++++++++++++++++ cli/internal/cli/update_test.go | 6 +++++ 4 files changed, 54 insertions(+), 15 deletions(-) create mode 100644 cli/internal/cli/dispatcher_update_version_test.go diff --git a/cli/internal/cli/dispatcher.go b/cli/internal/cli/dispatcher.go index b2e1aa287..50ee42b47 100644 --- a/cli/internal/cli/dispatcher.go +++ b/cli/internal/cli/dispatcher.go @@ -167,15 +167,16 @@ func enforceDispatcherFreshness(ctx context.Context, pin dispatcherPin, stderr i } func writeDispatcherSelfUpdateRequiredError(stderr io.Writer, updatedVersion string) { + currentVersion, nextVersion, changed := normalizedDispatcherUpdateVersions(dispatcherVersion, updatedVersion) message := "Dispatcher update completed. Retry the command so the updated dispatcher can run." - if dispatcherVersionChanged(dispatcherVersion, updatedVersion) { - message = "Dispatcher updated from " + dispatcherVersion + " to " + updatedVersion + ". Retry the command so the updated dispatcher can run." + if changed { + message = "Dispatcher updated from " + currentVersion + " to " + nextVersion + ". Retry the command so the updated dispatcher can run." } details := map[string]any{ - "CurrentDispatcherVersion": dispatcherVersion, + "CurrentDispatcherVersion": currentVersion, } - if updatedVersion != "" { - details["UpdatedDispatcherVersion"] = updatedVersion + if nextVersion != "" { + details["UpdatedDispatcherVersion"] = nextVersion } writeErrorEnvelope(stderr, cliError{ ErrorCode: errorCodeCLIUpdateRequired, diff --git a/cli/internal/cli/dispatcher_update_version.go b/cli/internal/cli/dispatcher_update_version.go index 68de26b6c..d899b277f 100644 --- a/cli/internal/cli/dispatcher_update_version.go +++ b/cli/internal/cli/dispatcher_update_version.go @@ -7,7 +7,6 @@ import ( "io" "os" "os/exec" - "strings" ) var dispatcherReadInstalledVersion = readInstalledDispatcherVersion @@ -52,20 +51,27 @@ func dispatcherInstalledVersionOrEmpty(ctx context.Context) string { } func dispatcherVersionChanged(fromVersion string, toVersion string) bool { - fromVersion = strings.TrimSpace(fromVersion) - toVersion = strings.TrimSpace(toVersion) - return fromVersion != "" && toVersion != "" && fromVersion != toVersion + _, _, changed := normalizedDispatcherUpdateVersions(fromVersion, toVersion) + return changed +} + +func normalizedDispatcherUpdateVersions(fromVersion string, toVersion string) (string, string, bool) { + normalizedFromVersion := normalizeDispatcherVersion(fromVersion) + normalizedToVersion := normalizeDispatcherVersion(toVersion) + changed := normalizedFromVersion != "" && normalizedToVersion != "" && normalizedFromVersion != normalizedToVersion + return normalizedFromVersion, normalizedToVersion, changed } func writeOptionalDispatcherUpdateCompletion(stderr io.Writer, fromVersion string, toVersion string) { - if !dispatcherVersionChanged(fromVersion, toVersion) { + normalizedFromVersion, normalizedToVersion, changed := normalizedDispatcherUpdateVersions(fromVersion, toVersion) + if !changed { return } writeFormat( stderr, "uloop: dispatcher updated from %s to %s. Future uloop commands will use the updated launcher.\n", - fromVersion, - toVersion) + normalizedFromVersion, + normalizedToVersion) } func writeManualDispatcherUpdateCompletion(stdout io.Writer, fromVersion string, toVersion string) { @@ -73,9 +79,10 @@ func writeManualDispatcherUpdateCompletion(stdout io.Writer, fromVersion string, writeLine(stdout, "uloop launcher update completed.") return } - if !dispatcherVersionChanged(fromVersion, toVersion) { - writeLine(stdout, "uloop launcher is already up to date at "+toVersion+".") + normalizedFromVersion, normalizedToVersion, changed := normalizedDispatcherUpdateVersions(fromVersion, toVersion) + if !changed { + writeLine(stdout, "uloop launcher is already up to date at "+normalizedToVersion+".") return } - writeLine(stdout, "uloop launcher updated from "+fromVersion+" to "+toVersion+".") + writeLine(stdout, "uloop launcher updated from "+normalizedFromVersion+" to "+normalizedToVersion+".") } diff --git a/cli/internal/cli/dispatcher_update_version_test.go b/cli/internal/cli/dispatcher_update_version_test.go new file mode 100644 index 000000000..cae545ca7 --- /dev/null +++ b/cli/internal/cli/dispatcher_update_version_test.go @@ -0,0 +1,25 @@ +package cli + +import ( + "bytes" + "testing" +) + +func TestDispatcherVersionChangedNormalizesVersionPrefix(t *testing.T) { + // Verifies v-prefixed and unprefixed dispatcher versions are treated as the same release. + if dispatcherVersionChanged("v3.0.1-beta.3", "3.0.1-beta.3") { + t.Fatal("expected equivalent dispatcher versions to be unchanged") + } +} + +func TestWriteOptionalDispatcherUpdateCompletionReportsNormalizedVersions(t *testing.T) { + // Verifies dispatcher update messages report canonical versions after prefix normalization. + var stderr bytes.Buffer + + writeOptionalDispatcherUpdateCompletion(&stderr, "v3.0.1-beta.2", "3.0.1-beta.3") + + expected := "uloop: dispatcher updated from 3.0.1-beta.2 to 3.0.1-beta.3" + if !bytes.Contains(stderr.Bytes(), []byte(expected)) { + t.Fatalf("update output mismatch: %s", stderr.String()) + } +} diff --git a/cli/internal/cli/update_test.go b/cli/internal/cli/update_test.go index 685492692..bbacb7414 100644 --- a/cli/internal/cli/update_test.go +++ b/cli/internal/cli/update_test.go @@ -208,6 +208,9 @@ func TestTryHandleUpdateRequestReportsVersionChange(t *testing.T) { if !bytes.Contains(stdout.Bytes(), []byte(expected)) { t.Fatalf("update output mismatch: %s", stdout.String()) } + if stderr.Len() != 0 { + t.Fatalf("expected no stderr output, got: %s", stderr.String()) + } } func TestTryHandleUpdateRequestReportsAlreadyCurrentVersion(t *testing.T) { @@ -227,6 +230,9 @@ func TestTryHandleUpdateRequestReportsAlreadyCurrentVersion(t *testing.T) { if !bytes.Contains(stdout.Bytes(), []byte(expected)) { t.Fatalf("update output mismatch: %s", stdout.String()) } + if stderr.Len() != 0 { + t.Fatalf("expected no stderr output, got: %s", stderr.String()) + } } func TestUpdateCommandForLinuxIsUnsupported(t *testing.T) {