From 9b6c8ad15624f8e6d1e7e6ddc529ab5d76d231b6 Mon Sep 17 00:00:00 2001 From: Matthew Edmondson Date: Thu, 8 Oct 2026 04:33:53 +0000 Subject: [PATCH] Take ktsu.RunCommand 1.9.5 so git output is read to EOF [patch] RunCommand 1.5.0 stopped reading when the process exited and made one final read, so output still in the pipe after it was dropped. Git output over ~8 KiB came back cut at 8,192 characters a few percent of the time, and Patch(), Log(), Status() and Diff() returned partial results without an error. RunCommand 1.8.0 reads to EOF (ktsu-dev/RunCommand#87). RunCommand 1.9.x needs ktsu.Semantics 5.x, so Semantics.Paths and Semantics.Strings move from 3.0.1 to 5.11.2 with it. The resolved graph is otherwise unchanged: Testably.Abstractions.FileSystem.Interface still resolves 10.0.0 and System.Text.Json's compile asset is still the framework placeholder on net9.0 and net10.0, so the KTSU0006 pins hold. The new test writes 60,000 characters in one burst and exits, 100 times, and asserts each run returns all of it. It fails on the first run with 1.5.0. Fixes #127 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01TJeQu4i8WTCDpvC4TN4Rjw --- Directory.Packages.props | 6 +-- .../RunCommandGitProcessRunnerTests.cs | 39 +++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index d8629d8..1169db7 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -7,9 +7,9 @@ - - - + + + diff --git a/GitIntegration.Test/Execution/RunCommandGitProcessRunnerTests.cs b/GitIntegration.Test/Execution/RunCommandGitProcessRunnerTests.cs index 0778f32..28800d3 100644 --- a/GitIntegration.Test/Execution/RunCommandGitProcessRunnerTests.cs +++ b/GitIntegration.Test/Execution/RunCommandGitProcessRunnerTests.cs @@ -286,6 +286,45 @@ public async Task ForcedEnvironmentReachesTheChildProcessAsync() Assert.AreEqual("0-C", result.StandardOutput.Trim()); } + [TestMethod] + public async Task CapturesAllOutputWrittenJustBeforeTheProcessExitsAsync() + { + // ktsu.RunCommand before 1.8.0 stopped reading when the process exited and then made one + // final read, so whatever was still in the pipe past that read was dropped: git output + // over ~8 KiB came back cut at 8,192 characters a few percent of the time, and Patch() + // returned short hunks (ktsu-dev/GitIntegration#127). A command that writes well over that + // in one burst and exits at once leaves the most in the pipe at exit, and it is repeated + // because whether a read loses the race is decided by scheduling. + const int Length = 60000; + string executable; + string[] arguments; + + if (OperatingSystem.IsWindows()) + { + executable = "powershell"; + arguments = ["-NoProfile", "-Command", $"[Console]::Out.Write('a' * {Length})"]; + } + else + { + executable = "sh"; + arguments = ["-c", $"head -c {Length} /dev/zero | tr '\\0' a"]; + } + + RunCommandGitProcessRunner runner = new(new GitOptions { ExecutablePath = executable }); + string expected = new('a', Length); + + for (int iteration = 0; iteration < 100; iteration++) + { + GitProcessResult result = await runner.RunAsync( + new GitProcessRequest { Arguments = arguments }, + TestContext.CancellationTokenSource.Token).ConfigureAwait(false); + + Assert.AreEqual(0, result.ExitCode); + Assert.AreEqual(expected.Length, result.StandardOutput.Length, $"Run {iteration} lost output."); + Assert.AreEqual(expected, result.StandardOutput, $"Run {iteration} returned different output."); + } + } + [TestMethod] public void EnvironmentOverlayForcesNonInteractiveEnglishGit() {