5.0 KiB
5.0 KiB
AGENTS.md
Build and Test Commands
Essential Setup
# Check Go version (requires 1.24.2+)
go version
# Check Helm dependency (required at runtime)
helm version # Must show version 3.x
# Install gci tool for import formatting
go install github.com/daixiang0/gci@latest
Build Commands
# Standard build
make build
# Direct build
go build -o helmfile .
# Cross-platform builds
make cross
# Build test tools (required for integration tests)
make build-test-tools
Linting and Formatting
# Run go vet (always available)
make check
# Format code with gci
make fmt
# Run golangci-lint
golangci-lint run
Testing Commands
# Run all unit tests
make test
# Run specific test package
go test -v ./pkg/app/...
# Run single test function
go test -v ./pkg/app/... -run TestSpecificFunction
# Run tests with coverage
go test -v ./pkg/... -coverprofile cover.out -race -p=1
go tool cover -func cover.out
# Run integration tests (requires Kubernetes cluster)
make integration
Code Style Guidelines
Imports
Import ordering (enforced by gci):
- Standard library (stdlib)
- Default (third-party)
- Local (github.com/helmfile/helmfile prefix)
Always use aliases for common stdlib packages to avoid conflicts:
import (
goContext "context" // Alias to avoid naming conflicts
goruntime "runtime"
"fmt"
"os"
"github.com/helmfile/helmfile/pkg/app"
)
Formatting
- Use
go fmtfor standard formatting - Use
gcifor import organization:gci write --skip-generated -s standard -s default -s 'prefix(github.com/helmfile/helmfile)' . - Run
make fmtbefore committing (requires gci installation)
Types
- Exported types use PascalCase:
type App struct - Private types use PascalCase:
type helmKey struct - Interface names should describe behavior:
type Interface interface - Use
anyinstead ofinterface{}
Naming Conventions
- Exported functions/variables: PascalCase
- Private functions/variables: camelCase
- Constants: PascalCase
- Test functions: TestXxx with descriptive names
- Package names: lowercase, single word when possible
- Error variables: ErrXxx
Error Handling
- Use fmt.Errorf with %w for wrapping errors
- Check errors explicitly; never ignore
- Use custom error types in pkg/errors/ when appropriate
- Return error as last return value
if err != nil {
return fmt.Errorf("failed to parse helm version '%s': %w", version, err)
}
Testing
- Use testify/assert for assertions:
assert.Equal(t, expected, actual) - Use testify/require for critical assertions:
require.NoError(t, err) - Test files: *_test.go
- Use table-driven tests for multiple scenarios
- Run tests with -race flag:
-race -p=1 - Use test helper packages: pkg/testutil, pkg/testhelper
func TestFunctionName(t *testing.T) {
tests := []struct {
name string
input string
want string
wantErr bool
}{
{
name: "valid input",
input: "test",
want: "result",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := FunctionUnderTest(tt.input)
if (err != nil) != tt.wantErr {
t.Errorf("error = %v, wantErr %v", err, tt.wantErr)
return
}
assert.Equal(t, tt.want, got)
})
}
}
Logging
- Use zap.SugaredLogger:
logger.Infof("message") - Logger injected via dependency injection
- Don't use fmt.Print for production logging
Comments
- Exported functions must have comments
- Comments should be complete sentences with capital first letter
- Use // for single-line comments
- Use /* */ for package documentation
Linting Configuration (from .golangci.yaml)
Key enabled linters:
- errcheck: Check unhandled errors
- staticcheck: Advanced static analysis
- revive: Fast linter
- govet: Go vet checks
- ineffassign: Detect ineffectual assignments
- misspell: Spell checking
- unused: Detect unused code
Important thresholds:
- Max function length: 280 lines
- Max statements per function: 140
- Max cognitive complexity: 110
- Max naked return lines: 50
- Line length: 120 characters
Structure
- Package main: Entry point only (main.go)
- cmd/: CLI commands using cobra
- pkg/: Core library code organized by domain
- test/: Integration and E2E tests
- Use dependency injection for testability
- Prefer composition over inheritance
Critical Rules
- Always handle errors
- Run
make checkbefore committing - Run
golangci-lint runand fix all issues - Write tests for new pkg/ functionality
- Update docs/ for user-facing changes
- Follow declarative design principles (desired state in config, operational via flags)
Common Issues
- First build downloads 200+ packages (2-3 minutes)
- Integration tests require Kubernetes cluster (minikube/kind)
- Make fmt requires gci installation
- Use -p=1 for tests to avoid race conditions
- Always initialize Helm plugins with
helmfile initafter installation