142 lines
No EOL
4.3 KiB
Text
142 lines
No EOL
4.3 KiB
Text
---
|
|
description: Standards for Go development, including installation paths and build preferences
|
|
globs: **/*.{go,mod,sum}
|
|
---
|
|
<rule>
|
|
When working with Go:
|
|
|
|
1. Installation and Path:
|
|
- Primary: Use Go from PATH if available
|
|
- Fallback: /usr/local/go/bin/go
|
|
- Always use command path resolution pattern from command-paths.mdc
|
|
|
|
2. Dependencies:
|
|
- Prefer pure Go implementations over CGO when available
|
|
- Examples:
|
|
- Use github.com/glebarez/sqlite over gorm.io/driver/sqlite
|
|
- Document any CGO dependencies in go.mod comments
|
|
|
|
3. Build Process:
|
|
- Always run `go mod tidy` after dependency changes
|
|
- Verify builds work without CGO: `CGO_ENABLED=0 go build`
|
|
- Use build.sh for full application builds
|
|
|
|
4. Module Management:
|
|
- Keep go.mod and go.sum in sync
|
|
- Document version constraints
|
|
- Run `go mod verify` before commits
|
|
|
|
5. HTTP Framework Standards:
|
|
- Use Gin for HTTP routing and middleware
|
|
- Group related routes under common prefixes
|
|
- Use consistent error response format:
|
|
```go
|
|
c.JSON(status, gin.H{"error": err.Error()})
|
|
```
|
|
- Leverage Gin's built-in features (binding, validation, etc.)
|
|
- Keep handlers focused and small
|
|
|
|
6. GORM Standards:
|
|
- Use struct tags for model definitions:
|
|
```go
|
|
type Model struct {
|
|
ID string `gorm:"primaryKey" json:"id"`
|
|
// Add json tags for all fields that need serialization
|
|
}
|
|
```
|
|
- Always handle GORM errors explicitly
|
|
- Use proper GORM hooks for timestamps (CreatedAt, UpdatedAt)
|
|
- Prefer query building over raw SQL
|
|
- Use transactions for multi-step operations
|
|
- Follow GORM naming conventions:
|
|
- Model names: singular, CamelCase
|
|
- Table names: plural, snake_case (auto-converted by GORM)
|
|
- Use appropriate GORM tags:
|
|
- `gorm:"primaryKey"` for primary keys
|
|
- `gorm:"not null"` for required fields
|
|
- `gorm:"index"` for indexed fields
|
|
- `gorm:"type:text"` for specific SQL types
|
|
|
|
7. Testing Standards:
|
|
- Place tests in _test.go files next to the code they test
|
|
- Use table-driven tests for multiple test cases
|
|
- Use meaningful test names that describe the scenario
|
|
- Create test helpers for common setup/teardown
|
|
- Use subtests for related test cases
|
|
- Test both success and error cases
|
|
- For database tests:
|
|
- Use in-memory SQLite for speed
|
|
- Clean up after each test
|
|
- Use transactions where appropriate
|
|
- Write focused tests that test one thing
|
|
- Include examples in test files when helpful
|
|
|
|
metadata:
|
|
priority: high
|
|
version: 1.0
|
|
</rule>
|
|
|
|
examples:
|
|
- input: |
|
|
# Bad: Using CGO-dependent SQLite
|
|
import "gorm.io/driver/sqlite"
|
|
output: |
|
|
# Good: Using pure Go SQLite
|
|
import "github.com/glebarez/sqlite"
|
|
|
|
- input: |
|
|
# Bad: Direct dependency add
|
|
go get some/package
|
|
output: |
|
|
# Good: Add dependency and tidy
|
|
go get some/package
|
|
go mod tidy
|
|
go mod verify
|
|
|
|
- input: |
|
|
# Bad: Flat route structure
|
|
r.GET("/notes", handleNotes)
|
|
r.GET("/notes/:id", handleNote)
|
|
output: |
|
|
# Good: Grouped routes
|
|
notes := r.Group("/notes")
|
|
{
|
|
notes.GET("", handleGetNotes)
|
|
notes.GET("/:id", handleGetNote)
|
|
}
|
|
|
|
- input: |
|
|
# Bad: Raw SQL and error handling
|
|
db.Exec("UPDATE notes SET content = ? WHERE id = ?", content, id)
|
|
output: |
|
|
# Good: GORM query building and error handling
|
|
if err := db.Model(&Note{}).Where("id = ?", id).Update("content", content).Error; err != nil {
|
|
return fmt.Errorf("failed to update note: %w", err)
|
|
}
|
|
|
|
- input: |
|
|
# Bad: Single monolithic test
|
|
func TestFeature(t *testing.T) {
|
|
// Test everything here
|
|
}
|
|
output: |
|
|
# Good: Table-driven tests with subtests
|
|
func TestFeature(t *testing.T) {
|
|
tests := []struct{
|
|
name string
|
|
input string
|
|
want string
|
|
}{
|
|
{"simple case", "input", "want"},
|
|
{"edge case", "edge", "result"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := Feature(tt.input)
|
|
if got != tt.want {
|
|
t.Errorf("got %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
} |