|
| 1 | +# AI Coding Agent Guidelines |
| 2 | + |
| 3 | +This document provides guidelines for AI coding agents working on the Testcontainers for Go repository. |
| 4 | + |
| 5 | +## Repository Overview |
| 6 | + |
| 7 | +This is a **Go monorepo** containing: |
| 8 | +- **Core library**: Root directory contains the main testcontainers-go library |
| 9 | +- **Modules**: `./modules/` directory with 50+ technology-specific modules (postgres, redis, kafka, etc.) |
| 10 | +- **Examples**: `./examples/` directory with example implementations |
| 11 | +- **Module generator**: `./modulegen/` directory with tools to generate new modules |
| 12 | +- **Documentation**: `./docs/` directory with MkDocs-based documentation |
| 13 | + |
| 14 | +## Environment Setup |
| 15 | + |
| 16 | +### Go Version |
| 17 | +- **Required**: Go 1.24.7 |
| 18 | +- **Tool**: Use [gvm](https://github.com/andrewkroh/gvm) for version management |
| 19 | +- **CRITICAL**: Always run this before ANY Go command: |
| 20 | + ```bash |
| 21 | + # For Apple Silicon (M1/M2/M3) |
| 22 | + eval "$(gvm 1.24.7 --arch=arm64)" |
| 23 | + |
| 24 | + # For Intel/AMD (x86_64) |
| 25 | + eval "$(gvm 1.24.7 --arch=amd64)" |
| 26 | + ``` |
| 27 | + |
| 28 | +### Project Structure |
| 29 | +Each module in `./modules/` is a separate Go module with: |
| 30 | +- `go.mod` / `go.sum` - Module dependencies |
| 31 | +- `{module}.go` - Main module implementation |
| 32 | +- `{module}_test.go` - Unit tests |
| 33 | +- `examples_test.go` - Testable examples for documentation |
| 34 | +- `Makefile` - Standard targets: `pre-commit`, `test-unit` |
| 35 | + |
| 36 | +## Development Workflow |
| 37 | + |
| 38 | +### Before Making Changes |
| 39 | +1. **Read existing code** in similar modules for patterns |
| 40 | +2. **Check documentation** in `docs/modules/index.md` for best practices |
| 41 | +3. **Run tests** to ensure baseline passes |
| 42 | + |
| 43 | +### Working with Modules |
| 44 | +1. **Change to module directory**: `cd modules/{module-name}` |
| 45 | +2. **Run pre-commit checks**: `make pre-commit` (linting, formatting, tidy) |
| 46 | +3. **Run tests**: `make test-unit` |
| 47 | +4. **Both together**: `make pre-commit test-unit` |
| 48 | + |
| 49 | +### Git Workflow |
| 50 | +- **Branch naming**: Use descriptive names like `chore-module-use-run`, `feat-add-xyz`, `fix-module-issue` |
| 51 | + - **NEVER** use `main` branch for PRs (they will be auto-closed) |
| 52 | +- **Commit format**: Conventional commits (enforced by CI) |
| 53 | + ```text |
| 54 | + type(scope): description |
| 55 | +
|
| 56 | + Longer explanation if needed. |
| 57 | +
|
| 58 | + 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
| 59 | +
|
| 60 | + Co-Authored-By: Claude <[email protected]> |
| 61 | + ``` |
| 62 | +- **Commit types** (enforced): `security`, `fix`, `feat`, `docs`, `chore`, `deps` |
| 63 | +- **Scope rules**: |
| 64 | + - Optional (can be omitted for repo-level changes) |
| 65 | + - Must be lowercase (uppercase scopes are rejected) |
| 66 | + - Examples: `feat(redis)`, `chore(kafka)`, `docs`, `fix(postgres)` |
| 67 | +- **Subject rules**: |
| 68 | + - Must NOT start with uppercase letter |
| 69 | + - ✅ Good: `feat(redis): add support for clustering` |
| 70 | + - ❌ Bad: `feat(redis): Add support for clustering` |
| 71 | +- **Breaking changes**: Add `!` after type: `feat(redis)!: remove deprecated API` |
| 72 | +- **Always include co-author footer** when AI assists with changes |
| 73 | + |
| 74 | +### Pull Requests |
| 75 | +- **Title format**: Same as commit format (validated by CI) |
| 76 | + - `type(scope): description` |
| 77 | + - Examples: `feat(redis): add clustering support`, `docs: improve module guide`, `chore(kafka): update tests` |
| 78 | +- **Title validation** enforced by `.github/workflows/conventions.yml` |
| 79 | +- **Labels**: Use appropriate labels (`chore`, `breaking change`, `documentation`, etc.) |
| 80 | +- **Body template**: |
| 81 | + ```markdown |
| 82 | + ## What does this PR do? |
| 83 | + |
| 84 | + Brief description of changes. |
| 85 | + |
| 86 | + ## Why is it important? |
| 87 | + |
| 88 | + Context and rationale. |
| 89 | + |
| 90 | + ## Related issues |
| 91 | + |
| 92 | + - Relates to #issue-number |
| 93 | + ``` |
| 94 | + |
| 95 | +## Module Development Best Practices |
| 96 | + |
| 97 | +**📖 Detailed guide**: See [`docs/modules/index.md`](docs/modules/index.md) for comprehensive module development documentation. |
| 98 | + |
| 99 | +### Quick Reference |
| 100 | + |
| 101 | +#### Container Struct |
| 102 | +- **Name**: Use `Container`, not module-specific names like `PostgresContainer` |
| 103 | +- **Fields**: Use private fields for state management |
| 104 | +- **Embedding**: Always embed `testcontainers.Container` |
| 105 | + |
| 106 | +```go |
| 107 | +type Container struct { |
| 108 | + testcontainers.Container |
| 109 | + dbName string // private |
| 110 | + user string // private |
| 111 | +} |
| 112 | +``` |
| 113 | + |
| 114 | +#### Run Function Pattern |
| 115 | +Five-step implementation: |
| 116 | +1. Process custom options (if using intermediate settings) |
| 117 | +2. Build `moduleOpts` with defaults |
| 118 | +3. Add conditional options based on settings |
| 119 | +4. Append user options (allows overrides) |
| 120 | +5. Call `testcontainers.Run` and return with proper error wrapping |
| 121 | + |
| 122 | +```go |
| 123 | +func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*Container, error) { |
| 124 | + // See docs/modules/index.md for complete implementation |
| 125 | + moduleOpts := []testcontainers.ContainerCustomizer{ |
| 126 | + testcontainers.WithExposedPorts("5432/tcp"), |
| 127 | + // ... defaults |
| 128 | + } |
| 129 | + moduleOpts = append(moduleOpts, opts...) |
| 130 | + |
| 131 | + ctr, err := testcontainers.Run(ctx, img, moduleOpts...) |
| 132 | + if err != nil { |
| 133 | + return nil, fmt.Errorf("run modulename: %w", err) |
| 134 | + } |
| 135 | + return &Container{Container: ctr}, nil |
| 136 | +} |
| 137 | +``` |
| 138 | + |
| 139 | +#### Container Options |
| 140 | +- **Simple config**: Use built-in `testcontainers.With*` options |
| 141 | +- **Complex logic**: Use `testcontainers.CustomizeRequestOption` |
| 142 | +- **State transfer**: Create custom `Option` type |
| 143 | + |
| 144 | +**Critical rules:** |
| 145 | +- ✅ Return struct types (not interfaces) |
| 146 | +- ✅ Call built-in options directly: `testcontainers.WithFiles(f)(req)` |
| 147 | +- ❌ Don't use `.Customize()` method |
| 148 | +- ❌ Don't pass slices to variadic functions |
| 149 | + |
| 150 | +#### Common Patterns |
| 151 | +- **Env inspection**: Use `strings.CutPrefix` with early exit |
| 152 | +- **Variadic args**: Pass directly, not as slices |
| 153 | +- **Option order**: defaults → user options → post-processing |
| 154 | +- **Error format**: `fmt.Errorf("run modulename: %w", err)` |
| 155 | + |
| 156 | +**For complete examples and detailed explanations**, see [`docs/modules/index.md`](docs/modules/index.md). |
| 157 | + |
| 158 | +## Testing Guidelines |
| 159 | + |
| 160 | +### Running Tests |
| 161 | +- **From module directory**: `cd modules/{module} && make test-unit` |
| 162 | +- **Pre-commit checks**: `make pre-commit` (run this first to catch lint issues) |
| 163 | +- **Full check**: `make pre-commit test-unit` |
| 164 | + |
| 165 | +### Test Patterns |
| 166 | +- Use testable examples in `examples_test.go` |
| 167 | +- Follow existing test patterns in similar modules |
| 168 | +- Test both success and error cases |
| 169 | +- Use `t.Parallel()` when tests are independent |
| 170 | + |
| 171 | +### When Tests Fail |
| 172 | +1. **Read the error message carefully** - it usually tells you exactly what's wrong |
| 173 | +2. **Check if it's a lint issue** - run `make pre-commit` first |
| 174 | +3. **Verify Go version** - ensure using Go 1.24.7 |
| 175 | +4. **Check Docker** - some tests require Docker daemon running |
| 176 | + |
| 177 | +## Common Pitfalls to Avoid |
| 178 | + |
| 179 | +### Code Issues |
| 180 | +- ❌ Using interface types as return values |
| 181 | +- ❌ Forgetting to run `eval "$(gvm 1.24.7 --arch=arm64)"` |
| 182 | +- ❌ Not handling errors from built-in options |
| 183 | +- ❌ Using module-specific container names (`PostgresContainer`) |
| 184 | +- ❌ Calling `.Customize()` method instead of direct function call |
| 185 | + |
| 186 | +### Git Issues |
| 187 | +- ❌ Forgetting co-author footer in commits |
| 188 | +- ❌ Not running tests before committing |
| 189 | +- ❌ Committing files outside module scope (use `git add modules/{module}/`) |
| 190 | +- ❌ Using uppercase in scope: `feat(Redis)` → use `feat(redis)` |
| 191 | +- ❌ Starting subject with uppercase: `fix: Add feature` → use `fix: add feature` |
| 192 | +- ❌ Using wrong commit type (only: `security`, `fix`, `feat`, `docs`, `chore`, `deps`) |
| 193 | +- ❌ Creating PR from `main` branch (will be auto-closed) |
| 194 | + |
| 195 | +### Testing Issues |
| 196 | +- ❌ Running tests without pre-commit checks first |
| 197 | +- ❌ Not changing to module directory before running make |
| 198 | +- ❌ Forgetting to set Go version before testing |
| 199 | + |
| 200 | +## Reference Documentation |
| 201 | + |
| 202 | +For detailed information, see: |
| 203 | +- **Module development**: `docs/modules/index.md` - Comprehensive best practices |
| 204 | +- **Contributing**: `docs/contributing.md` - General contribution guidelines |
| 205 | +- **Modules catalog**: [testcontainers.com/modules](https://testcontainers.com/modules/?language=go) |
| 206 | +- **API docs**: [pkg.go.dev/github.com/testcontainers/testcontainers-go](https://pkg.go.dev/github.com/testcontainers/testcontainers-go) |
| 207 | + |
| 208 | +## Module Generator |
| 209 | + |
| 210 | +To create a new module: |
| 211 | + |
| 212 | +```bash |
| 213 | +cd modulegen |
| 214 | +go run . new module --name mymodule --image "docker.io/myimage:tag" |
| 215 | +``` |
| 216 | + |
| 217 | +This generates: |
| 218 | +- Module scaffolding with proper structure |
| 219 | +- Documentation template |
| 220 | +- Test files with examples |
| 221 | +- Makefile with standard targets |
| 222 | + |
| 223 | +The generator uses templates in `modulegen/_template/` that follow current best practices. |
| 224 | + |
| 225 | +## Need Help? |
| 226 | + |
| 227 | +- **Slack**: [testcontainers.slack.com](https://slack.testcontainers.org/) |
| 228 | +- **GitHub Discussions**: [github.com/testcontainers/testcontainers-go/discussions](https://github.com/testcontainers/testcontainers-go/discussions) |
| 229 | +- **Issues**: Check existing issues or create a new one with detailed context |
0 commit comments