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

164 lines
4.9 KiB
Markdown

---
title: Development
description: 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/*`:
```bash
go env -w GOPRIVATE=forge.lthn.ai/*
```
## Go Workspace
This module is part of the workspace defined at `~/Code/go.work`. After
cloning, run:
```bash
go work sync
```
## Running Tests
```bash
# 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:
```bash
go test ./...
go test -run TestRunner_RunAll ./...
go test -v -count=1 ./exec/...
```
## Quality Assurance
```bash
# Format, vet, lint, test
core go qa
# Full suite (includes race detector, vulnerability scan, security audit)
core go qa full
```
Individual commands:
```bash
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.