Thank you for your interest in contributing to Tuti CLI! This document provides guidelines and instructions for contributing to the project.
- Development Environment Setup
- Project Structure
- Code Style Guidelines
- Static Analysis
- Testing
- Commit Message Conventions
- Branch Strategy
- Pull Request Guidelines
- Development Workflow
- Getting Help
| Requirement | Minimum Version | Notes |
|---|---|---|
| Docker | 20.10+ | Docker Engine or Docker Desktop |
| Docker Compose | v2 | Usually bundled with Docker |
| Git | 2.x | Version control |
# Clone the repository
git clone https://github.com/tuti-cli/cli.git
cd cli
# Start Docker containers and install dependencies
make install
# Access container shell
make shell
# Verify installation
php tuti --version| Command | Description |
|---|---|
make install |
Start Docker and install dependencies |
make up |
Start Docker containers |
make down |
Stop Docker containers |
make shell |
Access container shell |
make logs |
View container logs |
make c <cmd> |
Run any composer command (e.g., make c test:unit) |
app/
├── Commands/ # Console commands grouped by domain
│ ├── Infrastructure/ # infra:start, infra:stop, infra:status
│ ├── Local/ # local:start, local:stop, local:logs
│ ├── Stack/ # stack:laravel, stack:wordpress, stack:init
│ └── Test/ # Testing/debugging commands
├── Concerns/ # Traits (HasBrandedOutput, etc.)
├── Contracts/ # Interfaces
├── Domain/ # Domain models, value objects
├── Enums/ # PHP enums (Theme, etc.)
├── Infrastructure/ # Implementations
├── Providers/ # Service providers
├── Services/ # Business logic services
└── Support/ # Helper functions
stubs/
├── stacks/ # Stack templates (laravel, wordpress)
│ └── {stack}/services/ # Service stubs (databases, cache, etc.)
└── infrastructure/ # Global infrastructure (Traefik)
tests/
├── Feature/ # Feature/Integration tests
│ ├── Concerns/ # Test helpers
│ └── Console/ # Command tests
├── Unit/ # Unit tests
├── Mocks/ # Test mocks
└── Pest.php # Pest configuration
All PHP code must follow these standards:
<?php
declare(strict_types=1);
namespace App\Services\Example;
final readonly class ExampleService
{
public function __construct(
private SomeDependency $dependency,
) {}
public function doSomething(string $input): string
{
if (empty($input)) {
return '';
}
return $this->dependency->process($input);
}
}| Rule | Description |
|---|---|
declare(strict_types=1) |
Required in every PHP file |
final |
All classes must be final |
final readonly |
Services should be immutable |
| Constructor injection | No property injection, no setters |
| Return types | Explicit return types on all methods |
| Type hints | Full type declarations everywhere |
| No PHPDoc | Skip PHPDoc for type-hinted code |
| PSR-12 | Formatting via Laravel Pint |
| Return early | Avoid else/elseif |
| Type | Convention | Example |
|---|---|---|
| Class | PascalCase | StackInitializationService |
| Method | camelCase | getStackPath() |
| Variable | camelCase | $stackName |
| Constant | UPPER_SNAKE | MAX_RETRIES |
| Interface | PascalCase + Interface | StackInstallerInterface |
| Command signature | category:action |
stack:laravel, local:start |
The project uses PHPStan at level 5+ for static analysis:
# Run static analysis
make c test:types
# Or directly
docker compose exec -T app composer test:typesRector is used for automated refactoring:
# Check what would be changed (dry-run)
make c test:refactor
# Apply fixes
make refactorThe project uses Pest with parallel execution for testing.
# Run all quality checks (refactor + lint + types + tests)
make c test
# Run only Pest tests
make c test:unit
# Run tests with coverage
make c test:coverage
# Run a specific test
docker compose exec -T app ./vendor/bin/pest --filter "test_name"| Command | Description |
|---|---|
make c test |
Run all checks (refactor, lint, types, unit) |
make c test:unit |
Run Pest tests (parallel) |
make c test:types |
PHPStan static analysis |
make c test:lint |
Pint format check (dry-run) |
make c test:refactor |
Rector check (dry-run) |
make c test:coverage |
Pest with coverage report |
make lint |
Fix formatting with Pint |
make refactor |
Fix code with Rector |
- Location:
tests/Feature/Console/for command tests - Naming:
{Category}{Command}Test.php(e.g.,InfraStartCommandTest.php) - Structure: Use
describe()blocks for organization - Test names: Descriptive (e.g.,
it('creates .tuti directory with correct structure'))
| Component | Target |
|---|---|
| Commands | >80% |
| Services | >90% |
| Helpers | >95% |
<?php
declare(strict_types=1);
use Tests\TestCase;
use App\Services\MyService;
describe('MyService', function () {
it('does something correctly', function () {
$service = app(MyService::class);
$result = $service->doSomething('input');
expect($result)->toBe('expected output');
});
});This project follows Conventional Commits format:
type(scope): subject
[optional body]
| Type | Description |
|---|---|
feat |
New feature |
fix |
Bug fix |
docs |
Documentation changes |
style |
Code style (formatting, semicolons) |
refactor |
Code refactoring |
test |
Adding or updating tests |
chore |
Maintenance tasks |
feat(local): add port conflict detection
fix(docker): resolve container naming issue
docs(readme): update installation instructions
test(stack): add tests for Laravel stack installer
chore(deps): update composer dependencies
| Branch | Purpose |
|---|---|
main |
Stable releases only |
develop |
Active development |
feature/* |
New features (e.g., feature/redis-support) |
fix/* |
Bug fixes (e.g., fix/port-conflict) |
docs/* |
Documentation updates (e.g., docs/api-reference) |
# For a new feature
git checkout -b feature/my-new-feature
# For a bug fix
git checkout -b fix/some-bug- Run all tests:
make c test - Fix formatting:
make lint - Fix refactoring:
make refactor - Update documentation if needed
## Summary
- Brief description of changes
- Why these changes were made
## Test plan
- [ ] Unit tests added/updated
- [ ] All tests pass locally
- [ ] Manual testing completed
## Screenshots (if applicable)- All CI checks must pass (GitHub Actions)
- Code must follow project conventions
- New code should have appropriate test coverage
- Breaking changes must be documented
# Start development environment
make up
# Access container shell
make shell
# Make your changes...
# Run tests
make c test
# Fix formatting
make lint# Build PHAR (required before binary)
make build-phar
# Test PHAR works
make test-phar
# Build native binaries (all platforms)
make build-binary
# Build for specific platform
make build-binary-linux
make build-binary-mac
# Install locally for testing
make install-local
~/.tuti/bin/tuti --versionAll code must pass these checks before merging:
- Rector - No refactoring suggestions
- Pint - PSR-12 formatting
- PHPStan - Static analysis passes
- Pest - All tests pass
These run automatically in CI via GitHub Actions.
IMPORTANT: All external process execution must use array syntax to prevent shell injection:
// ✅ Safe - Array syntax
Process::run(['docker', 'info']);
// ❌ Unsafe - String interpolation
Process::run("docker info {$arg}");
// ❌ Unsafe - Imploded string
Process::run(implode(' ', $parts));- Never interpolate variables into shell command strings
- Never use
escapeshellarg()/escapeshellcmd()- array syntax handles escaping - Docker commands should go through
DockerExecutorServiceorDockerComposeOrchestrator
- Issues: GitHub Issues
- Discussions: GitHub Discussions
When reporting issues, please include:
- Your operating system and version
- Docker and Docker Compose versions (
docker --version,docker compose version) - Steps to reproduce the issue
- Expected vs actual behavior
- Any relevant logs or error messages
By contributing to Tuti CLI, you agree that your contributions will be licensed under the MIT License.
Thank you for contributing!