Thank you for your interest in contributing to SAI CLI! This guide will help you get started with contributing to the project.
- Code of Conduct
- Getting Started
- Ways to Contribute
- Development Setup
- Contributing Code
- Contributing Providers
- Contributing Documentation
- Submitting Changes
- Review Process
- Community
This project and everyone participating in it is governed by our Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to sai@example42.com.
- Go 1.21 or later
- Git
- Make
- Basic understanding of YAML and command-line tools
- Fork the repository on GitHub
- Clone your fork locally:
git clone https://github.com/example42/sai.git cd sai - Set up the development environment:
make deps make build make test - Create a branch for your changes:
git checkout -b feature/my-new-feature
Found a bug? Please create an issue with:
- Clear description of the problem
- Steps to reproduce
- Expected vs actual behavior
- System information (
sai stats --system --verbose) - SAI version (
sai version --verbose)
Have an idea? Start a discussion:
- Describe the use case
- Explain the expected behavior
- Consider implementation approaches
- Discuss potential alternatives
Documentation improvements are always welcome:
- Fix typos and grammar
- Add examples and use cases
- Improve clarity and organization
- Translate to other languages
Providers are the easiest way to contribute:
- Add support for new package managers
- Create specialized tool providers
- Improve existing provider configurations
- Add OS-specific overrides
Code contributions include:
- Bug fixes
- New features
- Performance improvements
- Test coverage improvements
- Refactoring and cleanup
-
Install Go 1.21+:
# Check version go version -
Install development tools:
make deps
-
Verify setup:
make verify-env make test make lint
├── cmd/sai/ # Main application entry point
├── internal/ # Private application code
│ ├── cli/ # CLI command implementations
│ ├── action/ # Action management
│ ├── provider/ # Provider loading and management
│ ├── saidata/ # Software data management
│ ├── template/ # Template engine
│ └── ... # Other internal packages
├── docs/ # Documentation
├── providers/ # Provider YAML files
├── schemas/ # JSON Schema files
├── scripts/ # Build and installation scripts
└── .github/workflows/ # CI/CD workflows
- Make changes in your feature branch
- Add tests for new functionality
- Run tests locally:
make test make lint make build - Test manually:
./build/sai install nginx --dry-run --verbose
- Commit changes with clear messages
- Push to your fork and create a pull request
- Go Style: Follow Effective Go guidelines
- Formatting: Use
gofmtandgoimports - Linting: Pass
golangci-lintchecks - Testing: Maintain or improve test coverage
- Documentation: Include godoc comments for public APIs
// Example unit test
func TestProviderManager_LoadProviders(t *testing.T) {
manager := NewProviderManager()
err := manager.LoadProviders("testdata/providers")
assert.NoError(t, err)
providers := manager.GetAvailableProviders()
assert.NotEmpty(t, providers)
}
// Example integration test
func TestCLI_InstallCommand(t *testing.T) {
cmd := exec.Command("./build/sai", "install", "nginx", "--dry-run")
output, err := cmd.CombinedOutput()
assert.NoError(t, err)
assert.Contains(t, string(output), "apt install")
}-
Create command file in
internal/cli/:// internal/cli/mycommand.go func NewMyCommand() *cobra.Command { cmd := &cobra.Command{ Use: "mycommand", Short: "Description of my command", RunE: runMyCommand, } return cmd }
-
Add to root command in
internal/cli/root.go:rootCmd.AddCommand(NewMyCommand())
-
Write tests in
internal/cli/mycommand_test.go -
Update documentation
Use structured errors with context:
import "github.com/pkg/errors"
func (m *Manager) LoadProvider(path string) error {
data, err := os.ReadFile(path)
if err != nil {
return errors.Wrapf(err, "failed to read provider file: %s", path)
}
var provider ProviderData
if err := yaml.Unmarshal(data, &provider); err != nil {
return errors.Wrapf(err, "failed to parse provider YAML: %s", path)
}
return nil
}Providers are the easiest way to contribute! They're defined in YAML files and don't require Go knowledge.
-
Choose provider type:
- Package manager (apt, dnf, etc.)
- Container platform (docker, podman)
- Language package manager (npm, pip)
- Specialized tool (security, monitoring)
-
Create provider file:
# providers/my-provider.yaml version: "1.0" provider: name: "my-provider" display_name: "My Package Manager" type: "package_manager" platforms: ["linux"] executable: "mypkg" priority: 50 actions: install: description: "Install package" template: "mypkg install {{sai_package}}" requires_root: true timeout: 300 validation: command: "mypkg list | grep -q '^{{sai_package}}$'" rollback: "mypkg remove {{sai_package}}"
-
Test the provider:
# Validate syntax sai stats --provider my-provider # Test with dry-run sai install nginx --provider my-provider --dry-run
-
Add documentation and examples
- Use descriptive names and clear descriptions
- Support multiple platforms when possible
- Include validation commands for safety
- Provide rollback procedures for destructive actions
- Test on target platforms thoroughly
- Follow existing provider patterns
For debugging, security, monitoring, and other specialized tools:
# providers/specialized/security-scanner.yaml
version: "1.0"
provider:
name: "security-scanner"
display_name: "Security Scanner"
type: "security"
platforms: ["linux", "darwin"]
executable: "scanner"
actions:
check:
description: "Run security scan"
template: "scanner scan {{sai_file 'binary'}} --format json"
timeout: 300
info:
description: "Show security information"
template: "scanner info {{.Software}}"- User guides: Help users accomplish tasks
- API documentation: Document code interfaces
- Examples: Show real-world usage
- Troubleshooting: Help solve common problems
- Clear and concise: Use simple language
- Practical examples: Include working code samples
- Up-to-date: Keep in sync with code changes
- Well-organized: Use consistent structure
- Accessible: Consider different skill levels
### Installing Web Servers
Install and start Nginx:
```bash
# Install Nginx
sai install nginx
# Start the service
sai start nginx
# Enable at boot
sai enable nginx
# Check status
sai status nginxThis will:
- Detect the best package manager for your system
- Install the nginx package
- Start the nginx service
- Configure it to start automatically at boot
- Show the current service status
## Submitting Changes
### Pull Request Process
1. **Create a feature branch**:
```bash
git checkout -b feature/my-feature
-
Make your changes with clear, focused commits:
git add . git commit -m "feat: add support for new package manager"
-
Push to your fork:
git push origin feature/my-feature
-
Create a pull request on GitHub with:
- Clear title and description
- Reference to related issues
- Screenshots/examples if applicable
- Checklist of changes made
Use Conventional Commits:
type(scope): description
[optional body]
[optional footer]
Types:
feat: New featurefix: Bug fixdocs: Documentation changesstyle: Code style changesrefactor: Code refactoringtest: Test additions/changeschore: Maintenance tasks
Examples:
feat(provider): add support for pacman package manager
fix(cli): resolve template resolution error for missing saidata
docs(examples): add MongoDB configuration examples
- Code follows project style guidelines
- Self-review of code completed
- Tests added for new functionality
- All tests pass locally
- Documentation updated
- Commit messages follow convention
- No merge conflicts with main branch
- Automated checks: CI/CD runs tests and linting
- Maintainer review: Code review by project maintainers
- Feedback incorporation: Address review comments
- Final approval: Merge when ready
- Functionality: Does it work as intended?
- Code quality: Is it well-written and maintainable?
- Testing: Are there adequate tests?
- Documentation: Is it properly documented?
- Compatibility: Does it work across platforms?
- Performance: Does it impact performance?
- Be responsive: Address feedback promptly
- Ask questions: Clarify unclear feedback
- Make changes: Update code based on suggestions
- Test thoroughly: Ensure changes work correctly
- Update documentation: Keep docs in sync
- GitHub Issues: Bug reports and feature requests
- GitHub Discussions: Questions and general discussion
- Pull Requests: Code review and collaboration
- Email: sai@example42.com for private matters
- Documentation: Check existing docs first
- Search issues: Look for similar problems
- Ask questions: Use GitHub Discussions
- Join discussions: Participate in community conversations
Contributors are recognized through:
- Contributors list: Listed in README and releases
- Release notes: Contributions mentioned in changelogs
- Special thanks: Recognition for significant contributions
# Development workflow
make build-dev # Build with race detection
make test # Run all tests
make test-coverage # Run tests with coverage
make lint # Run linter
make fmt # Format code
# Testing specific components
go test ./internal/provider/...
go test -run TestProviderManager
# Manual testing
./build/sai install nginx --dry-run --verbose
./build/sai stats --providers# Enable debug logging
export SAI_LOG_LEVEL=debug
./build/sai install nginx --verbose
# Use delve debugger
dlv debug ./cmd/sai -- install nginx --dry-run# Benchmark tests
go test -bench=. ./internal/...
# Memory profiling
go test -memprofile=mem.prof ./internal/provider/
go tool pprof mem.profYour contributions make SAI CLI better for everyone. Whether you're fixing a typo, adding a provider, or implementing a major feature, every contribution is valuable and appreciated.
Happy contributing! 🚀
For questions about contributing, please:
- 📖 Read the documentation
- 💬 Start a discussion
- 📧 Email us at sai@example42.com