dev

package module
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 6, 2026 License: Apache-2.0 Imports: 29 Imported by: 0

README

dev

go tool dev runs an app's whole development setup in one terminal: Postgres 18 and an S3-compatible server natively, with data kept between runs; its Go servers, rebuilt and restarted when their sources change; and processes beside them, such as Vite. Add it to the tools module (not the service's module: the S3 emulator's MD5 ETags fail under fips140=only), and describe the app in dev.json at the repository root:

go -C tools get -tool github.com/parallelworks/foundation/dev/cmd/dev
{
  "name": "shop",
  "postgres": { "parameters": { "max_connections": "300" } },
  "s3": {},
  "env": {
    "SHOP_DATABASE_URL": "{postgres}",
    "SHOP_TEST_DATABASE_URL": "{postgres_test}",
    "SHOP_S3_ENDPOINT": "{s3}",
    "SHOP_VITE_URL": "http://localhost:5173"
  },
  "services": [
    {
      "name": "server",
      "build": ["go", "build", "-o", "tmp/shop", "./cmd/shop"],
      "run": ["tmp/shop", "serve"],
      "exclude": ["tmp", "web", "tools"],
      "extensions": [".go", ".sql"]
    },
    { "name": "web", "run": ["pnpm", "--filter", "web", "dev"] }
  ]
}
Command
dev [service...] Run the stack and the services named, or every service not marked manual, until interrupted. Each line is prefixed with its source
dev logs service [-f] Print a service's output from the latest run, and with -f keep following it
dev stack Run Postgres on :5432 and S3 on 127.0.0.1:8333 until interrupted. User, password and database are name (required with Postgres); tests get name_test
dev wait Block until a stack started elsewhere accepts connections
dev reset Delete the stack's data

Data and each service's latest log live in .devstack/ beside dev.json, or --dir. The command finds dev.json from the working directory up, so go -C tools tool dev works too. A Postgres left running by a stack that was killed is stopped on the next start.

Services

A service with build is a server: built, run, and rebuilt and restarted when a file with one of its extensions (default .go) changes under its watch directories (default its dir). A build that fails stops it until the next change, so nothing runs stale code, and only one service builds at a time, so several servers do not exhaust a laptop's memory. A service without build runs once; if it exits, it is left stopped so its error is not buried under restarts.

Each service runs in its dir, relative to dev.json. Each command runs in its own process group, and stopping one ends everything it started, such as the Vite under pnpm. Unix only.

Environment

Every command gets, from lowest to highest precedence: env in dev.json; the service's own env; envFile (default .env beside dev.json, skipped when missing); the service's envFile, relative to its dir; and the real environment, so SHOP_LOG_LEVEL=info go tool dev overrides everything. Values in env may name the stack: {postgres} and {postgres_test} are database URLs, and {s3} is the S3 endpoint. Keep .env for secrets and personal settings.

before commands run once, in order, before anything starts, such as generating files a server embeds. If one fails, dev stops with its error.

Your own command

An app with its own development tasks builds its command on the same base:

func main() {
	root := dev.NewRootCmd(dev.Config{Name: "shop", Postgres: &dev.Postgres{}, S3: &dev.S3{}})
	root.AddCommand(seedCmd)
	ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
	defer stop()
	if err := root.ExecuteContext(ctx); err != nil {
		os.Exit(1)
	}
}

Documentation

Overview

Package dev runs a web service's local development dependencies without Docker, and is the base for an app's own development command.

Index

Constants

View Source
const ConfigFile = "dev.json"

ConfigFile is the name the dev command looks for, from the working directory up, so that `go -C tools tool dev` still finds the repository's.

Variables

This section is empty.

Functions

func FindConfig

func FindConfig(dir string) (string, error)

FindConfig returns the path of the nearest dev.json in dir or its parents.

func LogPath added in v0.4.0

func LogPath(logs, service string) string

LogPath is where a service's output from the latest run is kept, given the directory of a stack's logs.

func NewRootCmd

func NewRootCmd(cfg Config) *cobra.Command

NewRootCmd returns the dev command with the standard subcommands. An app with its own development tasks adds them with AddCommand.

func ResetStack

func ResetStack(ctx context.Context, cfg Config, logger *slog.Logger) error

ResetStack deletes the stack's data. A server still running from the same directory is stopped first, since it would recreate files as they go.

func Up added in v0.2.0

func Up(ctx context.Context, cfg Config, logger *slog.Logger, out io.Writer, names ...string) error

Up runs the stack and the services until ctx ends: those named, or every service not marked Manual. Each service's output is prefixed with its name and also written to its log under cfg.Dir.

func WaitStack

func WaitStack(ctx context.Context, cfg Config, timeout time.Duration) error

WaitStack blocks until a stack started elsewhere accepts connections, so that a server started alongside it does not race it.

Types

type Config

type Config struct {
	// Name is the Postgres user, password and database, and required with
	// Postgres. Tests get Name_test.
	Name string `json:"name"`
	// Root is the directory commands run in and relative paths resolve
	// against. LoadConfig sets it to the config file's directory; otherwise
	// it defaults to the working directory.
	Root string `json:"-"`
	// Dir keeps Postgres data, S3 objects and service logs between runs;
	// defaults to .devstack.
	Dir string `json:"dir,omitempty"`
	// Env is set for every command. Values may name the stack:
	// {postgres} and {postgres_test} are database URLs, {s3} the S3 endpoint.
	Env map[string]string `json:"env,omitempty"`
	// EnvFile is a dotenv file for personal settings and secrets, over Env
	// and under the real environment. Defaults to .env; a missing file is
	// skipped.
	EnvFile string `json:"envFile,omitempty"`
	// Postgres runs when set.
	Postgres *Postgres `json:"postgres,omitempty"`
	// S3 runs when set.
	S3 *S3 `json:"s3,omitempty"`
	// Before lists commands run once, in order, before anything starts, such
	// as generating files a server embeds. A failure stops dev.
	Before [][]string `json:"before,omitempty"`
	// Services run until dev stops: servers rebuilt when their sources
	// change, and processes such as a Vite dev server.
	Services []Service `json:"services,omitempty"`
}

Config describes an app's local stack.

func LoadConfig

func LoadConfig(path string) (Config, error)

LoadConfig reads a dev.json, rooted at its directory.

func (Config) DatabaseURL

func (c Config) DatabaseURL() string

DatabaseURL is the URL of the app's database, or "" without Postgres.

func (Config) TestDatabaseURL

func (c Config) TestDatabaseURL() string

TestDatabaseURL is the URL of the database for tests, or "" without Postgres.

type Postgres

type Postgres struct {
	// Port defaults to 5432.
	Port int `json:"port,omitempty"`
	// Parameters are server settings, e.g. max_connections for test suites
	// that open pools in parallel.
	Parameters map[string]string `json:"parameters,omitempty"`
}

Postgres configures the local PostgreSQL server.

type S3

type S3 struct {
	// Addr defaults to 127.0.0.1:8333.
	Addr string `json:"addr,omitempty"`
}

S3 configures the local S3-compatible server.

type Service added in v0.4.0

type Service struct {
	// Name prefixes its output, names its log, and selects it on the
	// command line.
	Name string `json:"name"`
	// Dir is where its commands run, relative to the root.
	Dir string `json:"dir,omitempty"`
	// Build compiles a server, e.g. ["go", "build", "-o", "tmp/shop", "./cmd/shop"].
	Build []string `json:"build,omitempty"`
	// Run starts it, e.g. ["tmp/shop", "serve"] or ["pnpm", "--filter", "web", "dev"].
	Run []string `json:"run"`
	// Watch lists the directories, relative to Dir, whose changes rebuild a
	// server; defaults to Dir. Hidden directories and node_modules are skipped.
	Watch []string `json:"watch,omitempty"`
	// Exclude names further directories to skip wherever they appear, such
	// as the frontend or the build output.
	Exclude []string `json:"exclude,omitempty"`
	// Extensions are the file types that rebuild a server; defaults to .go.
	Extensions []string `json:"extensions,omitempty"`
	// Env is set for this service over the config's Env, with the same
	// references to the stack.
	Env map[string]string `json:"env,omitempty"`
	// EnvFile is a dotenv file for this service, relative to Dir, over the
	// config's EnvFile.
	EnvFile string `json:"envFile,omitempty"`
	// Manual services start only when named: `dev web worker`.
	Manual bool `json:"manual,omitempty"`
}

Service is a long-running command. With Build it is a server: built, run, and rebuilt and restarted when its sources change; a failed build stops it until the next change. Without, it runs once and is left stopped if it exits, so a startup error is not buried under restarts.

type Stack

type Stack struct {
	// contains filtered or unexported fields
}

Stack is a running set of local dependencies.

func StartStack

func StartStack(ctx context.Context, cfg Config, logger *slog.Logger) (*Stack, error)

StartStack starts the configured dependencies and returns once they accept connections. The first run downloads the Postgres binaries.

func (*Stack) Stop

func (s *Stack) Stop(ctx context.Context) error

Stop shuts the dependencies down; Postgres flushes its data first.

Directories

Path Synopsis
cmd
dev command
Command dev runs an app's local development stack as described by the nearest dev.json.
Command dev runs an app's local development stack as described by the nearest dev.json.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL