Contributing¶
Thank you for your interest in contributing to TerraTidy!
For the quick-start contributing guide, see CONTRIBUTING.md at the repository root.
This page provides the comprehensive development reference.
Getting Started¶
Prerequisites¶
- Go 1.26.1 or later
- mise task runner
- Git
Clone the Repository¶
Install Dependencies¶
Build¶
Run Tests¶
Development Workflow¶
Create a Branch¶
Make Changes¶
- Write your code
- Add tests
- Update documentation
Run Checks¶
# Format code
mise run fmt
# Run linter
mise run lint
# Run all tests
mise run test
# Build
mise run build
Commit¶
Follow Conventional Commits:
git commit -m "feat: add new style rule for attribute ordering"
git commit -m "fix: correct HCL parsing edge case"
git commit -m "docs: update installation instructions"
Create Pull Request¶
- Push your branch
- Open a PR against
main - Fill out the PR template
- Wait for review
Code Style¶
Go Code¶
- Follow Effective Go
- Use
gofmtfor formatting - Run
golangci-lintfor linting
Documentation¶
- Use clear, concise language
- Include code examples
- Keep lines under 100 characters
Testing¶
Unit Tests¶
func TestMyFunction(t *testing.T) {
tests := []struct {
name string
input string
expected string
}{
{"basic case", "input", "expected"},
{"edge case", "", ""},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := MyFunction(tt.input)
if result != tt.expected {
t.Errorf("got %v, want %v", result, tt.expected)
}
})
}
}
Integration Tests¶
Coverage¶
Adding New Features¶
New Engine¶
- Create package in
internal/engines/ - Implement
Engineinterface - Add command in
cmd/terratidy/ - Add configuration support
- Write tests
- Update documentation
New Rule¶
- Add rule to appropriate engine
- Implement
Ruleinterface - Add configuration options
- Write tests
- Document in rules reference
New Output Format¶
- Implement
Formatterinterface - Register in output factory
- Add CLI flag support
- Write tests
- Document usage
Project Structure¶
terratidy/
├── cmd/terratidy/ # CLI commands
├── internal/
│ ├── runner/ # Engine runner, parallel execution
│ ├── config/ # Configuration loading
│ ├── output/ # Output formatting
│ ├── engines/ # Engine implementations
│ ├── lsp/ # Language server
│ └── plugins/ # Plugin system
├── pkg/sdk/ # Public SDK
├── docs/ # Documentation
└── testdata/ # Test fixtures
Pre-commit Setup¶
Install pre-commit hooks for automatic checks on commit:
# pre-commit is installed by mise (see mise.toml)
mise install
pre-commit install
pre-commit install --hook-type commit-msg # Conventional commit validation
The hooks run formatting, linting, and commit message validation automatically.
CI Pipeline¶
The CI pipeline runs on every PR:
Test workflow (.github/workflows/test.yml):
- Build: Compiles on ubuntu, macOS, and Windows
- Tests:
go test -v -race -cover ./...with coverage collection - Linting: golangci-lint and revive
- Coverage: Uploaded to Codecov (ubuntu-only)
Security workflow (.github/workflows/security.yml):
- govulncheck: Scans Go dependencies for known vulnerabilities
- dependency-review: Reviews dependency changes in PRs for advisories
- gitleaks: Scans for accidentally committed secrets
- go-licenses: Verifies all dependencies use approved licenses
- zizmor: Scans GitHub Actions workflows for security issues
- gorelease: Checks
pkg/sdkAPI compatibility on PRs (only when SDK files change)
Fuzz workflow (.github/workflows/fuzz.yml):
- Runs fuzz tests for config parsing, HCL formatting, and YAML rule loading
- 30s on PRs, 5m weekly for deeper exploration
All checks must pass before merging. See Security for details on the scanning pipeline.
API Stability¶
The pkg/sdk package is the public API for rule authors. Changes to exported types and functions are checked by gorelease on every PR that modifies pkg/sdk/**. Breaking changes require a major version bump.
Commit Format¶
Follow Conventional Commits:
| Prefix | Use For |
|---|---|
feat: | New features |
fix: | Bug fixes |
docs: | Documentation changes |
test: | Test additions/changes |
chore: | Maintenance, dependencies |
refactor: | Code restructuring |
perf: | Performance improvements |
PR Requirements¶
- Clear description of what changed and why
- Tests for new behavior
- Updated documentation for user-facing changes
- All CI checks passing
- Conventional commit messages
Release Process¶
Releases are fully automated. Pushing a version tag triggers the pipeline:
- Bump version:
bump-my-version bump <part>(major, minor, patch, pre_n) - Push the tag:
git push origin v1.2.3 - The release workflow handles everything else:
- GoReleaser cross-compiles binaries, builds Docker images, and updates the Homebrew formula
- git-cliff generates release notes from conventional commits
- CHANGELOG.md is automatically updated and committed to main
- Version alias tags (e.g.,
v1,v1.2) are created for stable releases - Docker alias tags are updated (
:latestalways points to the latest stable release) - Checksums are signed with cosign and build provenance is attested
- SBOMs are generated for each release archive
- Post-release smoke tests verify the binary on ubuntu and macOS
- Homebrew formula is tested on macOS (stable releases only)
Getting Help¶
- Open an issue for bugs
- Use discussions for questions
Code of Conduct¶
Be respectful and inclusive. We follow the Contributor Covenant.
License¶
By contributing, you agree that your contributions will be licensed under the MIT License.