WeKnora deployment source with the reviewed wiki identity, summary and recovery fixes
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
// Package iostreams wraps stdout/stderr/stdin with TTY detection and color awareness.
|
||||
//
|
||||
// Tests swap the package-level singleton via SetForTest; production code reads
|
||||
// the global IO directly. (Tests must not call SetForTest from t.Parallel(),
|
||||
// since the swap is process-global.)
|
||||
package iostreams
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/mattn/go-isatty"
|
||||
)
|
||||
|
||||
// IOStreams holds standard I/O handles plus environment-derived flags.
|
||||
type IOStreams struct {
|
||||
In io.Reader
|
||||
Out io.Writer
|
||||
Err io.Writer
|
||||
|
||||
stdoutTTY bool
|
||||
stderrTTY bool
|
||||
}
|
||||
|
||||
// IO is the package-level singleton.
|
||||
var IO *IOStreams = newProduction()
|
||||
|
||||
func newProduction() *IOStreams {
|
||||
return &IOStreams{
|
||||
In: os.Stdin,
|
||||
Out: os.Stdout,
|
||||
Err: os.Stderr,
|
||||
stdoutTTY: isatty.IsTerminal(os.Stdout.Fd()) || isatty.IsCygwinTerminal(os.Stdout.Fd()),
|
||||
stderrTTY: isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd()),
|
||||
}
|
||||
}
|
||||
|
||||
// IsStdoutTTY reports whether stdout is a terminal.
|
||||
func (s *IOStreams) IsStdoutTTY() bool { return s.stdoutTTY }
|
||||
|
||||
// IsStderrTTY reports whether stderr is a terminal.
|
||||
func (s *IOStreams) IsStderrTTY() bool { return s.stderrTTY }
|
||||
|
||||
// SetForTest replaces the package singleton with in-memory buffers for the
|
||||
// duration of t. Call it once per test. Not safe under t.Parallel().
|
||||
func SetForTest(t *testing.T) (out, errBuf *bytes.Buffer) {
|
||||
t.Helper()
|
||||
saved := IO
|
||||
out = &bytes.Buffer{}
|
||||
errBuf = &bytes.Buffer{}
|
||||
IO = &IOStreams{In: bytes.NewReader(nil), Out: out, Err: errBuf}
|
||||
t.Cleanup(func() { IO = saved })
|
||||
return out, errBuf
|
||||
}
|
||||
|
||||
// SetForTestWithTTY is like SetForTest but reports IsStdoutTTY/IsStderrTTY
|
||||
// = true so tests can exercise interactive code paths (confirm prompts,
|
||||
// color, fancy renderers). Not safe under t.Parallel().
|
||||
func SetForTestWithTTY(t *testing.T) (out, errBuf *bytes.Buffer) {
|
||||
t.Helper()
|
||||
saved := IO
|
||||
out = &bytes.Buffer{}
|
||||
errBuf = &bytes.Buffer{}
|
||||
IO = &IOStreams{
|
||||
In: bytes.NewReader(nil),
|
||||
Out: out,
|
||||
Err: errBuf,
|
||||
stdoutTTY: true,
|
||||
stderrTTY: true,
|
||||
}
|
||||
t.Cleanup(func() { IO = saved })
|
||||
return out, errBuf
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package iostreams
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSetForTest(t *testing.T) {
|
||||
out, errBuf := SetForTest(t)
|
||||
IO.Out.Write([]byte("stdout"))
|
||||
IO.Err.Write([]byte("stderr"))
|
||||
assert.Equal(t, "stdout", out.String())
|
||||
assert.Equal(t, "stderr", errBuf.String())
|
||||
}
|
||||
|
||||
func TestSetForTest_RestoresSingleton(t *testing.T) {
|
||||
original := IO
|
||||
t.Run("nested", func(t *testing.T) {
|
||||
SetForTest(t)
|
||||
assert.NotSame(t, original, IO)
|
||||
})
|
||||
// After the subtest's t.Cleanup runs, IO must be restored.
|
||||
assert.Same(t, original, IO)
|
||||
}
|
||||
|
||||
func TestProductionGetters(t *testing.T) {
|
||||
// We can't reliably assert the *value* of these (depends on whether tests
|
||||
// run in a TTY) but we can ensure the methods don't panic and return
|
||||
// consistent values across calls.
|
||||
p := newProduction()
|
||||
a, b := p.IsStdoutTTY(), p.IsStderrTTY()
|
||||
assert.Equal(t, a, p.IsStdoutTTY())
|
||||
assert.Equal(t, b, p.IsStderrTTY())
|
||||
}
|
||||
Reference in New Issue
Block a user