Delegate git process invocation to ktsu.RunCommand [patch] - #51
Conversation
GitRunner now runs git through RunCommand.ExecuteAsync instead of driving a Process by hand. RunCommand owns starting the process, reading both streams, killing the whole tree on cancellation, and giving up on reads once the process is gone. GitRunner keeps what is particular to git: the GIT_* and GIT_CONFIG_* environment, strict UTF-8 decoding, and telling its own timeout apart from the caller giving up. - Standard input is closed through StandardInputMode.Closed (RunCommand 1.9.0). - The environment is built as an overlay. Each inherited GIT_* variable maps to null, which removes it from the child's environment. - A decode failure is still reported as a GitResult, including when it arrives wrapped. - The bounded post-kill drain (DrainTimeout) goes away. RunCommand abandons the reads after a kill instead of waiting for a pipe a grandchild holds open. New tests cover a command that reads standard input, and output that is not valid UTF-8, both alone and mixed with valid text. Fixes #27 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TAvt7dvjcukkH3y6mtUL16
|
CI red: Cause: RunCommand's Fix: ktsu-dev/RunCommand#94 also calls I ran this test locally, 8 times each, with this repo pointed at the RunCommand project:
Why it isn't ported here: the fix lives inside the package, and Generated by Claude Code |
…o-runcommand # Conflicts: # Directory.Packages.props
|
Merged CI will likely stay red on ubuntu/windows. Generated by Claude Code |
RunCommand 1.9.1 kills the process tree whenever a cancelled wait ends the call (ktsu-dev/RunCommand#94). Before that, GitRunner's timeout could return with the tree still running, which failed RunAsync_ExceedingItsTimeout_ReportsTimedOutAndKillsTheTree on every CI leg. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TAvt7dvjcukkH3y6mtUL16
|



GitRunner.RunAsyncnow runs git throughRunCommand.ExecuteAsync(ktsu.RunCommand 1.9.0) instead of driving aProcessby hand. This follows the maintainer decision on the issue. RunCommand#82 has shipped, andDrainTimeoutis not a blocker.What moved to RunCommand
That last point replaces
DrainTimeout. RunCommand abandons the pending reads after a kill rather than waiting for a pipe that a surviving grandchild might hold open.Kill,DrainAsyncandBuildStartInfoare removed.What stays in GitRunner
ApplyEnvironment(ProcessStartInfo, …)becomesBuildEnvironment(invocation, settings, inherited), which returns the overlay forCommandOptions.EnvironmentVariables. It keeps the same flags and the sameGIT_CONFIG_*credential protocol. Each inheritedGIT_*variable now maps tonull, which removes it from the child's environment.StandardInputMode.Closed, which keeps the no-hang guaranteeprocess.StandardInput.Close()gave.OutputHandler. A decode failure is still reported as the existing "not valid UTF-8"GitResult, including when it arrives wrapped in another exception.Path.GetFullPathbefore becoming anAbsoluteDirectoryPath. A relative path still means relative to the current directory, as it did before.Tests
ApplyEnvironment_*tests now targetBuildEnvironment. The inherited-GIT_DIRtest asserts the overlay'snull, and a new assertion checks that non-git variables are left out of the overlay.RunAsync_ACommandThatReadsStandardInput_SeesEndOfStreamRatherThanWaitingRunAsync_OutputThatIsNotUtf8_IsReportedRatherThanReadAsEmptyOrReplaced, covering invalid bytes alone and invalid bytes mixed with valid text. These are the two cases the 2026-09-21 triage recorded. POSIX only, viaOSCondition.Full suite: 219 passed locally (net10.0, Linux).
This is a refactor, so the new tests also pass on
main. They pin guarantees the swap could have broken, and I checked that each one catches that:StandardInputtoInheritmakes the stdin test fail, "The command waited on standard input until it was killed", when the test host's stdin is an open pipe (sleep 200 | dotnet test …). If CI's stdin is/dev/null, this test cannot catch that regression there.DecoderFallbackException.dotnet format --verify-no-changesreports nothing in the changed files. The two findings it does report, inRealRepositoryTests.csandMirrorStartupCheck.cs, are also onmain.Fixes #27
🤖 Generated with Claude Code
https://claude.ai/code/session_01TAvt7dvjcukkH3y6mtUL16
Generated by Claude Code