Thank you for your interest in contributing to Timecapsule! This document provides guidelines and information for contributors.
Timecapsule is a lightweight Go library for storing time-locked values. It provides a simple, type-safe API for creating "time capsules" that unlock values at specified times.
- Go 1.21+ (check with
go version) - Git for version control
- Make (optional, for using the Makefile)
-
Fork and Clone
git clone https://github.com/YOUR_USERNAME/timecapsule.git cd timecapsule -
Install Dependencies
go mod download go mod tidy
-
Run Tests
go test -v go test -race -v # Test for race conditions
-
Run with Coverage
go test -v -cover go test -v -coverprofile=coverage.out go tool cover -html=coverage.out # View coverage in browser
-
Format and Lint
go fmt ./... go vet ./...
Before creating an issue, please:
- Search existing issues to avoid duplicates
- Use a clear, descriptive title
- Provide reproduction steps for bugs
- Include Go version and OS information
- Add relevant code samples when applicable
Bug Report Template:
## Bug Description
Brief description of the issue
## Steps to Reproduce
1. Step 1
2. Step 2
3. Step 3
## Expected Behavior
What should happen
## Actual Behavior
What actually happens
## Environment
- Go version: `go version`
- OS:
- timecapsule version:
## Code Sample
```go
// Minimal code to reproduce the issue
```When requesting features:
- Explain the use case and problem being solved
- Provide examples of the proposed API
- Consider backwards compatibility
- Check the roadmap to see if it's already planned
-
Create a feature branch
git checkout -b feature/your-feature-name # or git checkout -b fix/issue-description -
Make your changes
- Follow the coding standards
- Add tests for new functionality
- Update documentation if needed
- Ensure all tests pass
-
Commit your changes
git add . git commit -m "feat: add new time capsule feature" # or git commit -m "fix: resolve unlock time calculation bug"
-
Push and create PR
git push origin feature/your-feature-name
-
Fill out the PR template with:
- Description of changes
- Related issue links
- Testing details
- Breaking changes (if any)
- Follow standard Go formatting: Use
go fmtandgo vet - Use meaningful variable names:
unlockTimenott - Add comments for exported functions: Follow Go documentation conventions
- Keep functions focused: Single responsibility principle
- Prefer composition over inheritance
// Store saves a time-locked value that becomes accessible at unlockTime.
// The value is serialized using the configured codec and stored in the backend.
// Returns an error if the key already exists or storage fails.
func (tc *MemoryTimeCapsule[T]) Store(ctx context.Context, key string, value T, unlockTime time.Time) error {
// implementation
}-
Use sentinel errors for common error types:
var ( ErrCapsuleLocked = errors.New("capsule is still locked") ErrCapsuleNotFound = errors.New("capsule not found") ErrInvalidKey = errors.New("invalid key") )
-
Wrap errors with context:
if err != nil { return fmt.Errorf("failed to store capsule %q: %w", key, err) }
-
Test Coverage: Aim for >90% coverage
-
Table-driven tests for multiple scenarios:
func TestStore(t *testing.T) { tests := []struct { name string key string value string unlockTime time.Time expectError bool }{ { name: "valid storage", key: "test-key", value: "test-value", unlockTime: time.Now().Add(time.Hour), }, // more test cases... } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // test implementation }) } }
-
Test with context cancellation:
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) defer cancel()
-
Test race conditions:
go test -race ./... -
Example tests for documentation:
func ExampleTimeCapsule_Store() { capsule := timecapsule.New[string]() err := capsule.Store(context.Background(), "greeting", "Hello!", time.Now().Add(time.Hour)) fmt.Println(err == nil) // Output: true }
The library follows a simple, focused structure:
timecapsule/
├── timecapsule.go # Core interfaces and types
├── storage.go # Storage interface and implementations
├── codec.go # Serialization interface and implementations
├── example_test.go # Example tests for documentation
├── timecapsule_test.go # Unit tests
└── cmd/demo/ # Demo application
- Keep interfaces small and focused
- Use generics for type safety:
TimeCapsule[T any] - Accept interfaces, return structs
- Make zero values useful
When adding new storage backends:
- Implement the
Storageinterface - Handle context cancellation properly
- Add comprehensive tests
- Document configuration options
- Consider connection pooling and cleanup
Example:
type RedisStorage struct {
client *redis.Client
prefix string
}
func (r *RedisStorage) Store(ctx context.Context, key string, value []byte, unlockTime time.Time) error {
// Implementation with proper context handling
}# Basic tests
go test -v
# With race detection
go test -race -v
# With coverage
go test -v -cover
# Specific test
go test -run TestStore -v
# Benchmarks
go test -bench=. -v- Unit Tests: Test individual functions and methods
- Integration Tests: Test storage backends with real dependencies
- Race Tests: Ensure thread safety
- Example Tests: Validate documentation examples
- Benchmark Tests: Performance validation
- Use dependency injection for testability
- Create test helpers for common setup:
func setupTestCapsule(t *testing.T) TimeCapsule[string] { t.Helper() return New[string]() }
- Document all exported types and functions
- Use examples in documentation:
// Store saves a value with a future unlock time. // // Example: // capsule := timecapsule.New[string]() // err := capsule.Store(ctx, "key", "value", time.Now().Add(time.Hour)) func Store(ctx context.Context, key string, value T, unlockTime time.Time) error
When adding features:
- Update the feature list
- Add usage examples
- Update the API reference
- Add to use cases if applicable
Follow Keep a Changelog format:
## [1.2.0] - 2024-01-15
### Added
- Redis storage backend
- Bulk operations support
### Changed
- Improved error messages
### Fixed
- Race condition in memory storage- Features:
feature/add-redis-backend - Bug fixes:
fix/unlock-time-calculation - Documentation:
docs/improve-readme - Refactoring:
refactor/storage-interface
Follow Conventional Commits:
feat: add Redis storage backendfix: resolve race condition in memory storagedocs: update API documentationtest: add integration tests for storagerefactor: simplify codec interface
- Update version in relevant files
- Update CHANGELOG.md
- Create release notes
- Tag the release:
git tag v1.2.0 - Push tags:
git push origin --tags
We're especially interested in contributions for:
-
Storage Backends
- Redis implementation
- PostgreSQL/SQLite support
- File system backend
- Cloud storage options
-
Features
- TTL cleanup and auto-purging
- Bulk operations
- Encryption support
- Webhook notifications
-
Performance
- Benchmarking and optimization
- Memory usage improvements
- Concurrent access optimization
-
Developer Experience
- Better error messages
- More examples and tutorials
- CLI tools and utilities
- Documentation: Check the README and code comments
- Issues: Search existing issues
- Discussions: Use GitHub Discussions
- Chat: Join our community discussions
By contributing to timecapsule, you agree that your contributions will be licensed under the MIT License.
Thank you for contributing to timecapsule! 🚀