go-process/docs/development.md
Snider ec95200765 docs: add human-friendly documentation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 13:02:40 +00:00

4.9 KiB

title description
Development How to build, test, and contribute to go-process.

Development

Prerequisites

  • Go 1.26+ (uses Go workspaces)
  • Core CLI (core binary) for running tests and quality checks
  • Access to forge.lthn.ai (private module registry)

Ensure GOPRIVATE includes forge.lthn.ai/*:

go env -w GOPRIVATE=forge.lthn.ai/*

Go Workspace

This module is part of the workspace defined at ~/Code/go.work. After cloning, run:

go work sync

Running Tests

# All tests
core go test

# Single test
core go test --run TestService_Start

# With verbose output
core go test -v

Alternatively, using go test directly:

go test ./...
go test -run TestRunner_RunAll ./...
go test -v -count=1 ./exec/...

Quality Assurance

# Format, vet, lint, test
core go qa

# Full suite (includes race detector, vulnerability scan, security audit)
core go qa full

Individual commands:

core go fmt          # Format code
core go vet          # Go vet
core go lint         # Lint
core go cov          # Generate coverage report
core go cov --open   # Open coverage in browser

Test Naming Convention

Tests follow the _Good, _Bad, _Ugly suffix pattern used across the Core ecosystem:

  • _Good — happy path, expected success.
  • _Bad — expected error conditions, graceful handling.
  • _Ugly — panics, edge cases, degenerate inputs.

Where this pattern does not fit naturally, descriptive sub-test names are used instead (e.g. TestService_Start/echo_command, TestService_Start/context_cancellation).

Project Structure

go-process/
    .core/
        build.yaml          # Build configuration
        release.yaml        # Release configuration
    exec/
        exec.go             # Fluent command wrapper
        exec_test.go        # exec tests
        logger.go           # Logger interface and NopLogger
    actions.go              # IPC action message types
    buffer.go               # RingBuffer implementation
    buffer_test.go          # RingBuffer tests
    daemon.go               # Daemon lifecycle manager
    daemon_test.go          # Daemon tests
    go.mod                  # Module definition
    health.go               # HTTP health check server
    health_test.go          # Health server tests
    pidfile.go              # PID file single-instance lock
    pidfile_test.go         # PID file tests
    process.go              # Process type and methods
    process_global.go       # Global singleton and convenience API
    process_test.go         # Process tests
    global_test.go          # Global API tests (concurrency)
    registry.go             # Daemon registry (JSON file store)
    registry_test.go        # Registry tests
    runner.go               # Pipeline runner (sequential, parallel, DAG)
    runner_test.go          # Runner tests
    service.go              # Core service (DI integration, lifecycle)
    service_test.go         # Service tests
    types.go                # Shared types (Status, Stream, RunOptions, Info)

Adding a New Feature

  1. Write the implementation in the appropriate file (or create a new one if the feature is clearly distinct).
  2. Add tests following the naming conventions above.
  3. If the feature introduces new IPC events, add the message types to actions.go.
  4. Run core go qa to verify formatting, linting, and tests pass.
  5. Commit using conventional commits: feat(process): add XYZ support.

Coding Standards

  • UK English in documentation and comments (colour, organisation, centre).
  • declare(strict_types=1)-equivalent: all functions have explicit parameter and return types.
  • Error handling: return errors rather than panicking. Use sentinel errors (ErrProcessNotFound, ErrProcessNotRunning, ErrStdinNotAvailable) for well-known conditions.
  • Thread safety: all public types must be safe for concurrent use. Use sync.RWMutex for read-heavy workloads, sync.Mutex where writes dominate.
  • Formatting: gofmt / goimports via core go fmt.

Error Types

Error Meaning
ErrProcessNotFound No process with the given ID exists in the service
ErrProcessNotRunning Operation requires a running process (e.g. SendInput, Signal)
ErrStdinNotAvailable Stdin pipe is nil (already closed or never created)
ErrServiceNotInitialized Global convenience function called before process.Init()
ServiceError Wraps service-level errors with a message string

Build Configuration

The .core/build.yaml defines cross-compilation targets:

OS Architecture
linux amd64
linux arm64
darwin arm64
windows amd64

Since this is a library (no binary), the build configuration is primarily used for CI validation. The binary field is empty.

Licence

EUPL-1.2. See the repository root for the full licence text.