First off, thank you for considering contributing to Easy Commit! 🎉
This project follows a standard code of conduct based on the Contributor Covenant. By participating, you are expected to uphold this code and treat all contributors with respect.
Before creating bug reports, please check the issue tracker to avoid duplicates.
When creating a bug report, include:
- Clear title and description
- Steps to reproduce the behavior
- Expected vs actual behavior
- Environment details (OS, Bun version, Node version if applicable)
- Logs or error messages if applicable
- Version information (
easy-commit --version)
Enhancement suggestions are tracked as GitHub issues. When creating an enhancement suggestion:
- Use a clear and descriptive title
- Provide detailed explanation of the proposed feature
- Explain why this enhancement would be useful
- Include examples if applicable
- Fork the repository and create your branch from
main - Make your changes following our coding standards
- Add tests if applicable
- Ensure tests pass (
make test) - Update documentation if needed
- Commit using Conventional Commits (see below)
- Push to your fork and submit a pull request
You'll need:
- Bun v1.1 or later (installation guide)
- Git (obviously!)
- Node.js 18+ (optional, for npm compatibility)
# 1. Fork the repository on GitHub
# 2. Clone your fork
git clone https://github.com/YOUR_USERNAME/easy-commit.git
cd easy-commit
# 3. Install Bun (if not already installed)
curl -fsSL https://bun.sh/install | bash
# 4. Install dependencies
bun install
# 5. Verify setup works
bun run dev --version
# 6. Run tests to ensure everything is working
bun test# 1. Create a feature branch
git checkout -b feat/my-new-feature
# 2. Make your changes
# ...
# 3. Run linter and formatter
bun run lint:fix
bun run format
# 4. Type check
bun run typecheck
# 5. Run tests
bun test
# 6. Run tests with coverage (aim for >80%)
bun test --coverage
# 7. Test in dev mode
bun run dev
# 8. Build and test standalone binary
bun run build:standalone
./easy-commit --versionThis project uses Conventional Commits. All commits must follow this format:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
Types:
feat: New featurefix: Bug fixdocs: Documentation changesstyle: Code style changes (formatting, no logic change)refactor: Code refactoring (no behavior change)test: Adding or updating testschore: Maintenance tasksbuild: Build system changesci: CI configuration changesperf: Performance improvements
Examples:
feat: add support for custom commit templates
fix: resolve issue with scope validation
docs: update installation instructions
refactor: simplify validator logic
test: add tests for git executor
chore: update dependenciesUsing Easy Commit for Commits:
The best way to create commits for this project? Use easy-commit itself!
# Interactive mode (recommended)
bun run dev
# Or direct mode
bun run dev -t feat -m "add new feature"Breaking Changes:
Mark breaking changes by adding ! after the type or by including BREAKING CHANGE: in the footer:
feat!: change API structure for commit service
BREAKING CHANGE: The CommitService.Create method now requires a context parameter.# Run all tests
bun test
# Run tests in watch mode (for development)
bun test --watch
# Run with coverage
bun test --coverage
# Run specific test file
bun test tests/unit/domain/commit.test.ts
# Run E2E tests only
bun test tests/e2e/
# Run performance benchmarks
bun test tests/e2e/performance.test.tsCoverage Expectations:
- Domain layer: >90% coverage
- Application layer: >80% coverage
- Infrastructure layer: >70% coverage
- Overall: >80% coverage
This project uses Biome for linting and formatting (replaces ESLint + Prettier).
Key Style Guidelines:
- Use TypeScript strict mode (no
anywithout good reason) - Use
constoverlet, never usevar - Prefer
interfacefor object shapes,typefor unions/intersections - Use PascalCase for classes and types, camelCase for variables and functions
- File names: kebab-case (e.g.,
commit-service.ts) - Add JSDoc comments for exported functions and classes
- Keep functions small and focused
- Write descriptive test names
Automatic Formatting:
# Format all files
bun run format
# Check without modifying
bun run lint
# Fix linting issues automatically
bun run lint:fix
# Type check (no auto-fix)
bun run typecheckFile naming conventions:
- Source files:
kebab-case.ts(e.g.,commit-service.ts) - Test files:
kebab-case.test.ts(e.g.,commit-service.test.ts) - React components:
PascalCase.tsx(e.g.,CommitPreview.tsx) - Types/Interfaces: PascalCase in any
.tsfile
Easy Commit follows Clean Architecture with three layers:
Infrastructure → Application → Domain
Layer Responsibilities:
-
Domain Layer (
src/domain/):- Core business entities (Commit, CommitType)
- Value objects (Description, Scope)
- Repository interfaces
- Domain errors
- Pure TypeScript, no external dependencies
-
Application Layer (
src/application/):- Use cases and business workflows
- Services (CommitService)
- Validators (ConcurrentValidator)
- Depends only on domain layer
-
Infrastructure Layer (
src/infrastructure/):- External concerns (CLI, Git, Config, TUI, Logger)
- Framework-specific code (ink, commander, Bun APIs)
- Implements domain interfaces
- Depends on application and domain layers
Golden Rule: Always respect dependency direction. Never import from a higher layer into a lower layer.
// ✅ GOOD: Infrastructure imports from Application
import { CommitService } from '@application/services/CommitService';
// ❌ BAD: Domain imports from Infrastructure
import { GitExecutor } from '@infrastructure/git/GitExecutor';Additional Guidelines:
- Keep business logic in domain/application layers
- Keep framework code in infrastructure layer
- Use dependency injection for testability
- Write tests for each layer independently
See AGENTS.md for detailed architecture documentation and guidelines.
The interactive TUI is built with ink (React for terminal).
Key Concepts:
- Functional components with hooks
- Use
useStatefor local state - Use
useInputfor keyboard handling - Use
useEffectfor side effects
Screen Structure:
src/infrastructure/ui/
├── App.tsx # Main app component with state machine
├── components/ # Reusable components
├── screens/ # Wizard screens (7 screens)
├── hooks/ # Custom hooks
└── styles.ts # Colors and styling
Testing UI Components:
Use ink-testing-library for component tests:
import { render } from 'ink-testing-library';
import MyComponent from './MyComponent';
test('should render component', () => {
const { lastFrame } = render(<MyComponent />);
expect(lastFrame()).toContain('Expected text');
});Releases are automated using GitHub Actions and follow Semantic Versioning.
- MAJOR (v2.0.0): Breaking changes, incompatible API changes
- MINOR (v1.1.0): New features, backwards compatible
- PATCH (v1.0.1): Bug fixes, backwards compatible
The version is determined based on commit messages:
- Commits with
feat:increment MINOR - Commits with
fix:increment PATCH - Commits with
BREAKING CHANGE:or!increment MAJOR
- Ensure all changes are merged to
main - All tests pass on
mainbranch - Decide version number based on commits
- Create and push a tag:
# Decide version based on changes
# - Bug fixes only: patch (v1.0.1)
# - New features: minor (v1.1.0)
# - Breaking changes: major (v2.0.0)
git checkout main
git pull origin main
# Create annotated tag
git tag -a v1.0.1 -m "Release v1.0.1: Bug fixes and improvements"
# Push tag (triggers release workflow)
git push origin v1.0.1-
GitHub Actions will automatically:
- Run all tests (unit, integration, E2E)
- Type check and lint
- Build binaries for all platforms:
- Linux (x64, arm64)
- macOS (x64, arm64)
- Windows (x64)
- Generate CHANGELOG from commits
- Create compressed archives (.tar.gz)
- Generate SHA256 checksums
- Create GitHub release with artifacts
- Upload all binaries
-
Verify the release on GitHub Releases
For alpha, beta, or release candidate versions:
git tag v1.1.0-alpha.1 # Alpha release
git tag v1.1.0-beta.1 # Beta release
git tag v1.1.0-rc.1 # Release candidateGitHub Actions will automatically mark these as pre-releases.
Before creating a tag, test the build process:
# Build standalone binary
bun run build:standalone
# Test the binary
./easy-commit --version
./easy-commit --help
# Test interactive mode
cd /path/to/test/repo
/path/to/easy-commit
# Verify size and startup time
ls -lh easy-commit
time ./easy-commit --versionExpected Build Output:
- Binary size: ~50-60 MB
- Startup time: <100ms
- All features working
When making changes, update relevant documentation:
- README.md - User-facing features, installation, usage examples
- AGENTS.md - Architecture, development guidelines, project setup
- CONTRIBUTING.md - Contribution guidelines (this file)
- MIGRATION_GUIDE.md - Migration instructions from Go to TypeScript version
- Code comments - JSDoc for exported functions and classes
Documentation Standards:
- Keep examples up-to-date and working
- Include code examples for complex features
- Document all public APIs
- Update version numbers after releases
- Add screenshots/recordings for UI changes (optional)
Before submitting a PR, ensure:
- Code follows project style (Biome passes)
- Type checking passes (
bun run typecheck) - All tests pass (
bun test) - Coverage remains above 80% (
bun test --coverage) - New features have tests
- Documentation updated (if needed)
- Commit messages follow Conventional Commits
- PR description explains what/why, not just how
- No merge conflicts with
main - Local build works (
bun run build:standalone)
PR Title Format: Use Conventional Commits format:
feat: add custom commit templates
fix: resolve scope validation issue
docs: update README installation section
-
Update
src/domain/entities/commit-type.ts:export const COMMIT_TYPES: CommitType[] = [ // ... existing types { name: 'newtype', description: 'Description of new type' }, ];
-
Add tests in
tests/unit/domain/commit-type.test.ts -
Update README.md to document the new type
-
Run tests:
bun test
-
Create component in
src/infrastructure/ui/screens/ -
Implement React component with ink:
import { Box, Text } from 'ink'; import { useState } from 'react'; export default function MyScreen() { return <Box>...</Box>; }
-
Add to state machine in
App.tsx -
Add keyboard handling with
useInput -
Add integration test in
tests/integration/ui/
-
Update validators in
src/application/validators/concurrent-validator.ts -
Update config schema in
src/infrastructure/config/config-loader.ts -
Update
.easy-commit.example.yaml -
Add tests in
tests/unit/application/
-
Update
src/infrastructure/cli/cli-parser.ts -
Add new option to commander:
.option('--my-flag <value>', 'description')
-
Update help text
-
Update README.md usage section
-
Add tests in
tests/unit/infrastructure/cli-parser.test.ts
If you have questions or need help:
- Check AGENTS.md for project architecture and guidelines
- Check MIGRATION_GUIDE.md if migrating from Go version
- Check README.md for user documentation
- Search existing Issues
- Open a new Issue with questions
# Development
bun run dev # Run in development mode
bun run dev --help # Show help
# Testing
bun test # Run all tests
bun test --watch # Run tests in watch mode
bun test --coverage # Run with coverage
bun test tests/unit/ # Run unit tests only
bun test tests/e2e/ # Run E2E tests only
# Building
bun run build # Build to dist/
bun run build:standalone # Build standalone binary
bun run build:quick # Quick build (no version injection)
# Quality
bun run lint # Check code style
bun run lint:fix # Fix code style issues
bun run format # Format code
bun run typecheck # Type check
# Cleaning
bun run clean # Remove build artifacts- Runtime: Bun (ultra-fast JavaScript runtime)
- Language: TypeScript (strict mode)
- TUI: ink v6 (React for terminal)
- CLI: commander v14
- Config: js-yaml + Zod (validation)
- Testing: Bun test (Jest-compatible)
- Linting: Biome (replaces ESLint + Prettier)
- Build: Bun bundler + compiler
- Bun Documentation
- ink Documentation
- TypeScript Handbook
- Conventional Commits
- Clean Architecture
- Semantic Versioning
By contributing, you agree that your contributions will be licensed under the MIT License.