feat: improve resource routing API and add comprehensive quality standards
BREAKING CHANGES:
- Renamed HandleGET -> MemberGET for member-level routes
- Renamed HandlePOST -> MemberPOST for member-level routes
- Renamed HandlePUT -> MemberPUT for member-level routes
- Renamed HandlePATCH -> MemberPATCH for member-level routes
- Renamed HandleDELETE -> MemberDELETE for member-level routes
New Features:
- Added collection-level route methods: GET, POST, PUT, PATCH, DELETE
- Clear distinction between collection (/pattern/action) and member (/pattern/{id}/action) routes
- Comprehensive documentation (README, CONTRIBUTING, QUICKSTART, DOCS)
- Development tooling (Makefile, check.sh script)
- AI coding assistant guidelines (.cursorrules)
- GitHub Actions CI/CD pipeline
- golangci-lint configuration
Code Quality:
- Optimized struct field alignment for better memory usage
- All code passes go vet, staticcheck, and fieldalignment
- All tests pass with race detector
- Go 1.25+ requirement enforced
Documentation:
- Complete README rewrite with examples
- CONTRIBUTING.md with development guidelines
- QUICKSTART.md for new users
- CHANGELOG.md with version history
- SUMMARY.md documenting all changes
- DOCS.md as documentation index
This commit is contained in:
410
CONTRIBUTING.md
Normal file
410
CONTRIBUTING.md
Normal file
@@ -0,0 +1,410 @@
|
||||
# Contributing to Mux
|
||||
|
||||
Thank you for your interest in contributing to Mux! This document provides guidelines and standards for contributing to this project.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
Be respectful, constructive, and collaborative. We're all here to build better software together.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Go Version
|
||||
|
||||
This project requires **Go 1.25 or higher**. We leverage the latest Go features and improvements, so please ensure your development environment meets this requirement.
|
||||
|
||||
```bash
|
||||
go version # Should show go1.25 or higher
|
||||
```
|
||||
|
||||
### Development Tools
|
||||
|
||||
Before contributing, ensure you have the following tools installed:
|
||||
|
||||
```bash
|
||||
# Install staticcheck
|
||||
go install honnef.co/go/tools/cmd/staticcheck@latest
|
||||
|
||||
# Install fieldalignment (part of go vet)
|
||||
# This is included with Go 1.25+
|
||||
```
|
||||
|
||||
## Code Quality Standards
|
||||
|
||||
All code contributions **MUST** pass the following checks before being submitted:
|
||||
|
||||
### 1. go vet
|
||||
|
||||
Ensure your code passes `go vet` which catches common mistakes:
|
||||
|
||||
```bash
|
||||
go vet ./...
|
||||
```
|
||||
|
||||
**What it checks:**
|
||||
- Suspicious constructs
|
||||
- Printf-like function calls with incorrect arguments
|
||||
- Unreachable code
|
||||
- Common mistakes in error handling
|
||||
- And many other potential issues
|
||||
|
||||
### 2. fieldalignment
|
||||
|
||||
Ensure struct fields are optimally ordered to minimize memory usage:
|
||||
|
||||
```bash
|
||||
go vet -vettool=$(which fieldalignment) ./...
|
||||
```
|
||||
|
||||
Or use fieldalignment directly:
|
||||
|
||||
```bash
|
||||
fieldalignment -fix ./... # Automatically fix alignment issues
|
||||
```
|
||||
|
||||
**Why it matters:**
|
||||
- Reduces memory footprint
|
||||
- Improves cache locality
|
||||
- Better performance in memory-constrained environments
|
||||
|
||||
**Example:**
|
||||
```go
|
||||
// Bad - wastes memory due to padding
|
||||
type BadStruct struct {
|
||||
a bool // 1 byte + 7 bytes padding
|
||||
b int64 // 8 bytes
|
||||
c bool // 1 byte + 7 bytes padding
|
||||
}
|
||||
|
||||
// Good - optimally aligned
|
||||
type GoodStruct struct {
|
||||
b int64 // 8 bytes
|
||||
a bool // 1 byte
|
||||
c bool // 1 byte + 6 bytes padding
|
||||
}
|
||||
```
|
||||
|
||||
### 3. staticcheck
|
||||
|
||||
Run `staticcheck` to catch bugs and ensure code quality:
|
||||
|
||||
```bash
|
||||
staticcheck ./...
|
||||
```
|
||||
|
||||
**What it checks:**
|
||||
- Unused code
|
||||
- Inefficient code patterns
|
||||
- Deprecated API usage
|
||||
- Common bugs and mistakes
|
||||
- Style and consistency issues
|
||||
- Performance problems
|
||||
- Security vulnerabilities
|
||||
|
||||
### Pre-Submission Checklist
|
||||
|
||||
Before submitting a pull request, run all checks:
|
||||
|
||||
```bash
|
||||
# Run all checks
|
||||
go vet ./...
|
||||
staticcheck ./...
|
||||
go test ./...
|
||||
```
|
||||
|
||||
Create a simple script `check.sh` in your local environment:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "Running go vet..."
|
||||
go vet ./...
|
||||
|
||||
echo "Running staticcheck..."
|
||||
staticcheck ./...
|
||||
|
||||
echo "Running tests..."
|
||||
go test -race -v ./...
|
||||
|
||||
echo "Checking field alignment..."
|
||||
go vet -vettool=$(which fieldalignment) ./...
|
||||
|
||||
echo "All checks passed! ✅"
|
||||
```
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### 1. Fork and Clone
|
||||
|
||||
```bash
|
||||
git clone https://github.com/YOUR_USERNAME/mux.git
|
||||
cd mux
|
||||
```
|
||||
|
||||
### 2. Create a Branch
|
||||
|
||||
```bash
|
||||
git checkout -b feature/your-feature-name
|
||||
```
|
||||
|
||||
### 3. Make Your Changes
|
||||
|
||||
- Write clear, idiomatic Go code
|
||||
- Follow Go conventions and best practices
|
||||
- Keep functions small and focused
|
||||
- Add comments for exported functions and complex logic
|
||||
- Update documentation if needed
|
||||
|
||||
### 4. Write Tests
|
||||
|
||||
All new features and bug fixes should include tests:
|
||||
|
||||
```go
|
||||
func TestNewFeature(t *testing.T) {
|
||||
// Arrange
|
||||
m := mux.New()
|
||||
|
||||
// Act
|
||||
m.GET("/test", testHandler)
|
||||
|
||||
// Assert
|
||||
req := httptest.NewRequest(http.MethodGet, "/test", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
m.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Errorf("expected status 200, got %d", rec.Code)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Run Quality Checks
|
||||
|
||||
```bash
|
||||
go vet ./...
|
||||
staticcheck ./...
|
||||
go test -race ./...
|
||||
```
|
||||
|
||||
### 6. Commit Your Changes
|
||||
|
||||
Write clear, descriptive commit messages:
|
||||
|
||||
```bash
|
||||
git commit -m "feat: add support for custom error handlers"
|
||||
git commit -m "fix: resolve race condition in middleware chain"
|
||||
git commit -m "docs: update README with new examples"
|
||||
```
|
||||
|
||||
**Commit message prefixes:**
|
||||
- `feat:` - New feature
|
||||
- `fix:` - Bug fix
|
||||
- `docs:` - Documentation changes
|
||||
- `test:` - Test additions or modifications
|
||||
- `refactor:` - Code refactoring
|
||||
- `perf:` - Performance improvements
|
||||
- `chore:` - Maintenance tasks
|
||||
|
||||
### 7. Push and Create Pull Request
|
||||
|
||||
```bash
|
||||
git push origin feature/your-feature-name
|
||||
```
|
||||
|
||||
Then create a pull request on GitHub with:
|
||||
- Clear description of changes
|
||||
- Link to related issues (if any)
|
||||
- Screenshots/examples if applicable
|
||||
|
||||
## Code Style Guidelines
|
||||
|
||||
### General Principles
|
||||
|
||||
1. **Simplicity over cleverness** - Write clear, maintainable code
|
||||
2. **Use standard library** - Avoid external dependencies unless absolutely necessary
|
||||
3. **Zero allocation paths** - Optimize hot paths to minimize allocations
|
||||
4. **Fail fast** - Use panics for programmer errors, errors for runtime issues
|
||||
5. **Document public APIs** - All exported functions, types, and methods should have comments
|
||||
|
||||
### Naming Conventions
|
||||
|
||||
- Use short, descriptive names for local variables
|
||||
- Use full words for exported identifiers
|
||||
- Follow Go naming conventions (MixedCaps, not snake_case)
|
||||
- Avoid stuttering (e.g., `mux.MuxRouter` → `mux.Router`)
|
||||
|
||||
### Error Handling
|
||||
|
||||
```go
|
||||
// Good - clear error handling
|
||||
func processRequest(w http.ResponseWriter, r *http.Request) {
|
||||
data, err := fetchData(r.Context())
|
||||
if err != nil {
|
||||
http.Error(w, "Failed to fetch data", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
// process data...
|
||||
}
|
||||
|
||||
// Avoid - ignoring errors
|
||||
func processRequest(w http.ResponseWriter, r *http.Request) {
|
||||
data, _ := fetchData(r.Context()) // Don't do this
|
||||
// process data...
|
||||
}
|
||||
```
|
||||
|
||||
### Comments
|
||||
|
||||
```go
|
||||
// Good - explains why, not what
|
||||
// Use buffered channel to prevent goroutine leaks when context is cancelled
|
||||
// before the worker finishes processing.
|
||||
ch := make(chan result, 1)
|
||||
|
||||
// Avoid - states the obvious
|
||||
// Create a channel
|
||||
ch := make(chan result, 1)
|
||||
```
|
||||
|
||||
## Testing Guidelines
|
||||
|
||||
### Test Structure
|
||||
|
||||
Use the Arrange-Act-Assert pattern:
|
||||
|
||||
```go
|
||||
func TestRouteRegistration(t *testing.T) {
|
||||
// Arrange
|
||||
m := mux.New()
|
||||
handler := func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("test"))
|
||||
}
|
||||
|
||||
// Act
|
||||
m.GET("/test", handler)
|
||||
routes := m.RouteList()
|
||||
|
||||
// Assert
|
||||
if len(routes) != 1 {
|
||||
t.Errorf("expected 1 route, got %d", len(routes))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Table-Driven Tests
|
||||
|
||||
For testing multiple scenarios:
|
||||
|
||||
```go
|
||||
func TestPathParameters(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
pattern string
|
||||
path string
|
||||
expected string
|
||||
}{
|
||||
{"simple param", "/users/{id}", "/users/123", "123"},
|
||||
{"multiple params", "/posts/{year}/{month}", "/posts/2024/01", "2024"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// test implementation
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Test Coverage
|
||||
|
||||
Aim for high test coverage, especially for:
|
||||
- Public APIs
|
||||
- Edge cases
|
||||
- Error conditions
|
||||
- Concurrent access patterns
|
||||
|
||||
```bash
|
||||
# Check coverage
|
||||
go test -cover ./...
|
||||
|
||||
# Generate detailed coverage report
|
||||
go test -coverprofile=coverage.out ./...
|
||||
go tool cover -html=coverage.out
|
||||
```
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Benchmarking
|
||||
|
||||
Include benchmarks for performance-critical code:
|
||||
|
||||
```go
|
||||
func BenchmarkMiddlewareChain(b *testing.B) {
|
||||
m := mux.New()
|
||||
m.Use(middleware1, middleware2, middleware3)
|
||||
m.GET("/test", testHandler)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/test", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
m.ServeHTTP(rec, req)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Run benchmarks:
|
||||
|
||||
```bash
|
||||
go test -bench=. -benchmem ./...
|
||||
```
|
||||
|
||||
### Allocation Analysis
|
||||
|
||||
Identify and minimize allocations:
|
||||
|
||||
```bash
|
||||
go test -bench=. -benchmem -memprofile=mem.out ./...
|
||||
go tool pprof mem.out
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
### Code Documentation
|
||||
|
||||
- All exported functions, types, and methods must have comments
|
||||
- Comments should start with the name of the thing being described
|
||||
- Use complete sentences with proper punctuation
|
||||
|
||||
```go
|
||||
// New creates and returns a new Mux router instance with an empty route table
|
||||
// and no middleware configured.
|
||||
func New() *Mux {
|
||||
return &Mux{
|
||||
mux: http.NewServeMux(),
|
||||
routes: new(RouteList),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### README Updates
|
||||
|
||||
If your change affects usage:
|
||||
- Update relevant sections in README.md
|
||||
- Add examples if introducing new features
|
||||
- Update the table of contents if adding new sections
|
||||
|
||||
## Questions or Issues?
|
||||
|
||||
- Open an issue for bugs or feature requests
|
||||
- Start a discussion for questions or ideas
|
||||
- Check existing issues and PRs before creating new ones
|
||||
|
||||
## License
|
||||
|
||||
By contributing to Mux, you agree that your contributions will be licensed under the MIT License.
|
||||
|
||||
---
|
||||
|
||||
Thank you for contributing to Mux! Your efforts help make this project better for everyone. 🙏
|
||||
Reference in New Issue
Block a user