Skip to content

v2.3.0

Choose a tag to compare

@github-actions github-actions released this 11 Jul 00:54

Added

  • RecordReplayOptions.WithCwdMatching(): opt-in restoration of the working directory (Command.CurrentDir) as part of a ProcessKit.Testing cassette's replay match key.

Changed

  • ProcessKit.Testing cassette matching no longer keys on the working directory (Command.CurrentDir) by default: two otherwise-identical invocations recorded/replayed from different absolute directories (a developer's checkout vs. a CI runner's workspace) now match, instead of missing with ProcessError.CassetteMiss purely because of cwd. CassetteEntry.Cwd still stores the working directory verbatim for inspection. This is a behavioural change for an existing cassette that relied on cwd alone to distinguish two entries — those entries now collapse to the same match key and one of them "wins" (replays for both) in capture order; add RecordReplayOptions.WithCwdMatching() (applied symmetrically at record and replay time) to restore the previous cwd-sensitive matching.

Fixed

  • RunningProcess.WaitForAsync / WaitForPortAsync now enforce their timeout and cancellation as a
  • RunningProcess.WaitForPortAsync / WaitForAsync now background-drain the child's piped
  • ProcessKit.Testing cassette writes (RecordReplayRunner.Save/dispose) now flush the recorded content to disk before the atomic rename swaps it into place, and best-effort fsync the cassette's parent directory on Unix afterwards, so a crash right after a save can no longer leave the cassette file or the rename itself unpersisted.
  • Command.Retry/Supervisor now refuse a command whose stdin comes from a one-shot source (Stdin.FromStream/FromLines/FromAsyncLines) up front, with ProcessError.Unsupported, instead of silently re-running or restarting it against the already-exhausted source on the second attempt — previously the child could receive truncated or empty stdin without any error. Repeatable sources (FromString/FromBytes/FromFile/Stdin.Empty) and a single run without an active retry/restart are unaffected.
  • A buffered tee sink (Command.StdoutTee/StderrTee, e.g. a BufferedStream-backed writer) now gets flushed as soon as the pump's read loop ends — on both clean EOF and a read failure — instead of only once the caller eventually disposes it, so a consumer reading the tee concurrently no longer sees truncated output. ProcessKit still never disposes the caller-supplied tee.
  • On Windows, ProcessGroup.Suspend/Resume now re-verify (IsProcessInJob) that a job member's process handle is still actually a member of the job right after opening it, closing a narrow pid-reuse race: previously, if a member (typically a handle-less grandchild) exited and its pid was immediately reused by an unrelated process between the member snapshot and OpenProcess, that unrelated process could be frozen/thawed instead. The re-check is fail-safe (any failure to open the process or query its membership leaves it untouched) and the fix touches only this internal handle-acquisition step — no public API change.
  • On Linux, a failed cgroup.procs read (e.g. EACCES/EIO racing teardown) is no longer folded into an empty member list. Graceful shutdown and the kill fallback for the cgroup v2 limits backend now treat a read failure as "membership unknown, not drained," so they keep escalating instead of concluding the tree already exited early; ProcessGroup.Members/Stats propagate the read failure as an honest ProcessError.Io rather than reporting a fabricated empty group / zero active processes.
  • A genuine OS-level read failure on the child's stdout/stderr pipe now surfaces as ProcessError.Io from FinishAsync/WaitAsync/ProfileAsync/OutputStringAsync (and faults the streaming enumerator for StdoutLinesAsync/OutputEventsAsync), instead of silently ending the capture as if the child had produced a short, complete output. The routine dispose/broken-pipe race this library's own teardown triggers by design (closing the pipe streams while a still-running background pump may be mid-read) is still swallowed exactly as before — only a fault raised before teardown began is now reported.
  • On Linux, per-member cgroup v2 signal delivery is now identity-safe against pid recycling.
  • On the POSIX process-group backend (macOS/BSD, or Linux without cgroup delegation), every