--- name: go-code description: Go style rules. Use before you write or review Go code. --- # Go code ## Packages and files - Keep Go code in one root `main` package. Do not add `internal/`, `cmd/`, or one-file packages until the user asks for them. - Keep `main.go` limited to the entry point. Name other files for their function. Do not create `main_test.go`. - A file carries its own context. Keep each struct and all of its methods in one file. Give a separate responsibility its own type. - When code in one file gets a user in another file for an unrelated purpose, move it to a file named for its function in the same change. - Start each package-level name that belongs to one feature or integration with the name of that feature. Start the names of its files with the same name. Keep a name generic only when more than one feature uses it. - Write type names with a capital letter, so that a variable can have the name of its type. Write all other package-level names in lower case. - Write all the letters of an initialism in one case. - Put entry points first, then each struct's methods as a group, then standalone utility functions. Do not put a utility function between the methods of one type. - In each group, order functions by first use in the file. ## Entry point and context - `main` calls `run()` and handles its returned error. Do not use `log.Fatal`. - `run()` creates the SIGINT/SIGTERM signal context and defers its cancellation. Pass that context through operations and let cleanup finish before `main` exits. - Use `ctx` for a context and `cancel` for its cancellation function. Call `defer cancel()` immediately after you create the context. - Reuse `ctx` when a child context replaces its parent. Use a different name only when both contexts stay in use. Return `ctx.Err()` directly. ## Errors - Handle every returned error. - Reuse an existing `err` for later operations in the same scope. Use a different variable only to keep or join errors. - Use `errors.Is` and `errors.As` to examine errors. Do not compare an error directly with a sentinel, because errors can be wrapped. - When a function has more than one error path, wrap each returned error with the context of its operation. A function with one error path can return the error directly. - When deferred cleanup can fail, use a named `err` result and join the cleanup error with `errors.Join`. ## Style - Keep function signatures on one line. Write function bodies on more than one line, also for anonymous functions, deferred cleanup, and test callbacks. - Do not use short `if` initializers. - Use a one-letter receiver name for each method. - Use field names in struct literals. Put each field on its own line when you set more than one field. This includes the cases of a table-driven test. A small type of two fields that acts as one value, such as a key or a coordinate pair, can use a positional literal on one line. - Put an empty line between logical blocks, also after multiline declarations, assignments, literals, and calls. Keep an operation with its immediate error or result check. Keep a short declaration with its immediate use. - Use GNU-style command flags: two dashes for long flags, such as `--cwd`, and one dash only for one-letter flags, such as `-h`. - Prefer the Go standard library. Prefer Go over cgo. - Do not add compile-time interface assertions. Prove compatibility through actual assignments and calls. - Use `// nolint: name` for lint directives. ## Dependencies - After a change to `go.mod` or `go.sum`, update `vendorHash` in `nix/package.nix`. While the module has no dependencies, `vendorHash` is `null`. ## Tests - Add tests for meaningful behavior. Do not add tests that only repeat implementation details. - Use `testify/require` for assertions. - Name a table-driven case slice `testCases` and its range variable `tc`. A subtest name describes the behavior, not a generic outcome or input. - In a test file, put constants immediately after the imports, then the tests, then supporting types, methods, and helpers. - Supply valid required dependencies in tests. Do not make a dependency optional only to make a test simpler.