|
| 1 | +--- |
| 2 | +description: Coding standards and style rules for the Git Auto Deployment Tool project |
| 3 | +globs: ["**/*.php", "**/*.yml", "**/*.yaml", "**/*.json"] |
| 4 | +--- |
| 5 | + |
| 6 | +# Git Auto Deployment Tool - Coding Standards |
| 7 | + |
| 8 | +## PHP Code Style |
| 9 | + |
| 10 | +This project uses **PHP CS Fixer** with custom rules. All code MUST pass the linter before being committed. |
| 11 | + |
| 12 | +### Running the Linter |
| 13 | + |
| 14 | +```bash |
| 15 | +# Check for issues (dry-run) |
| 16 | +./linter/lint.sh --dry-run |
| 17 | + |
| 18 | +# Fix issues automatically |
| 19 | +./linter/lint.sh |
| 20 | +``` |
| 21 | + |
| 22 | +### Key Style Rules |
| 23 | + |
| 24 | +#### 1. Array Syntax |
| 25 | +- ✅ Use short array syntax: `[]` |
| 26 | +- ❌ Don't use: `array()` |
| 27 | + |
| 28 | +```php |
| 29 | +// Good |
| 30 | +$items = ['foo', 'bar']; |
| 31 | + |
| 32 | +// Bad |
| 33 | +$items = array('foo', 'bar'); |
| 34 | +``` |
| 35 | + |
| 36 | +#### 2. Braces Position |
| 37 | +- Opening braces on the **same line** as the declaration |
| 38 | +- Applies to: classes, functions, control structures |
| 39 | + |
| 40 | +```php |
| 41 | +// Good |
| 42 | +class MyClass { |
| 43 | + public function myMethod(): void { |
| 44 | + if ($condition) { |
| 45 | + // code |
| 46 | + } |
| 47 | + } |
| 48 | +} |
| 49 | + |
| 50 | +// Bad |
| 51 | +class MyClass |
| 52 | +{ |
| 53 | + public function myMethod(): void |
| 54 | + { |
| 55 | + if ($condition) |
| 56 | + { |
| 57 | + // code |
| 58 | + } |
| 59 | + } |
| 60 | +} |
| 61 | +``` |
| 62 | + |
| 63 | +#### 3. Whitespace Rules |
| 64 | +- **NO trailing whitespace** at end of lines |
| 65 | +- **NO whitespace in blank lines** - blank lines must be completely empty |
| 66 | +- Single blank line at end of file |
| 67 | +- Whitespace after commas in arrays |
| 68 | +- Space before and after operators (except `=` and `=>` for alignment) |
| 69 | + |
| 70 | +```php |
| 71 | +// Good |
| 72 | +$arr = ['a', 'b', 'c']; |
| 73 | +$result = $a + $b; |
| 74 | + |
| 75 | +// Empty line below (no spaces) |
| 76 | + |
| 77 | +$another = 'value'; |
| 78 | + |
| 79 | +// Bad |
| 80 | +$arr = ['a','b','c']; |
| 81 | +$result = $a+$b; |
| 82 | + |
| 83 | +$another = 'value'; // trailing spaces |
| 84 | +``` |
| 85 | + |
| 86 | +#### 4. Imports |
| 87 | +- Remove unused imports |
| 88 | +- No leading slash in imports |
| 89 | +- Sort imports alphabetically |
| 90 | + |
| 91 | +```php |
| 92 | +// Good |
| 93 | +use Mariano\GitAutoDeploy\ConfigReader; |
| 94 | +use Mariano\GitAutoDeploy\Request; |
| 95 | +use Monolog\Logger; |
| 96 | + |
| 97 | +// Bad |
| 98 | +use \Mariano\GitAutoDeploy\ConfigReader; |
| 99 | +use Mariano\GitAutoDeploy\UnusedClass; |
| 100 | +``` |
| 101 | + |
| 102 | +#### 5. Function and Method Declarations |
| 103 | +- Type hints for parameters and return types when possible |
| 104 | +- No space after function name |
| 105 | +- Space before colon in return types |
| 106 | + |
| 107 | +```php |
| 108 | +// Good |
| 109 | +public function getData(string $key): array { |
| 110 | + return []; |
| 111 | +} |
| 112 | + |
| 113 | +// Bad |
| 114 | +public function getData ($key) { |
| 115 | + return []; |
| 116 | +} |
| 117 | +``` |
| 118 | + |
| 119 | +#### 6. Class Structure |
| 120 | +- One blank line between methods |
| 121 | +- Properties before methods |
| 122 | +- Public methods before private methods |
| 123 | + |
| 124 | +```php |
| 125 | +class Example { |
| 126 | + private $property; |
| 127 | + |
| 128 | + public function publicMethod(): void { |
| 129 | + // code |
| 130 | + } |
| 131 | + |
| 132 | + private function privateMethod(): void { |
| 133 | + // code |
| 134 | + } |
| 135 | +} |
| 136 | +``` |
| 137 | + |
| 138 | +## PSR-12 Compliance |
| 139 | + |
| 140 | +This project follows PSR-12 coding standard with custom modifications listed above. |
| 141 | + |
| 142 | +## Testing Standards |
| 143 | + |
| 144 | +### Test Files |
| 145 | +- All test files must be in the `test/` directory |
| 146 | +- Test class names must end with `Test` |
| 147 | +- Use PHPUnit framework |
| 148 | +- Test methods must start with `test` |
| 149 | + |
| 150 | +### Test Structure |
| 151 | +```php |
| 152 | +class MyFeatureTest extends TestCase { |
| 153 | + private $subject; |
| 154 | + private $mockDependency; |
| 155 | + |
| 156 | + public function setUp(): void { |
| 157 | + parent::setUp(); |
| 158 | + $this->mockDependency = $this->createMock(Dependency::class); |
| 159 | + $this->subject = new MyFeature($this->mockDependency); |
| 160 | + } |
| 161 | + |
| 162 | + public function testFeatureBehavesCorrectly(): void { |
| 163 | + // Arrange |
| 164 | + $this->mockDependency->expects($this->once()) |
| 165 | + ->method('doSomething') |
| 166 | + ->willReturn('result'); |
| 167 | + |
| 168 | + // Act |
| 169 | + $result = $this->subject->execute(); |
| 170 | + |
| 171 | + // Assert |
| 172 | + $this->assertEquals('expected', $result); |
| 173 | + } |
| 174 | +} |
| 175 | +``` |
| 176 | + |
| 177 | +## Git Commit Messages |
| 178 | + |
| 179 | +### Format |
| 180 | +``` |
| 181 | +type(scope): brief description |
| 182 | + |
| 183 | +Longer description if needed. |
| 184 | + |
| 185 | +- Bullet points for details |
| 186 | +- Multiple points if necessary |
| 187 | +``` |
| 188 | + |
| 189 | +### Types |
| 190 | +- `feat`: New feature |
| 191 | +- `fix`: Bug fix |
| 192 | +- `refactor`: Code refactoring |
| 193 | +- `test`: Adding or updating tests |
| 194 | +- `docs`: Documentation changes |
| 195 | +- `chore`: Maintenance tasks |
| 196 | +- `style`: Code style changes (formatting, etc.) |
| 197 | +- `perf`: Performance improvements |
| 198 | + |
| 199 | +### Examples |
| 200 | +``` |
| 201 | +feat(runner): add placeholder hydration for pre/post fetch commands |
| 202 | + |
| 203 | +fix(security): prevent injection in custom commands |
| 204 | + |
| 205 | +test(runner): add coverage for secret placeholders in deploy commands |
| 206 | + |
| 207 | +chore: update GitHub Actions to v4 |
| 208 | +``` |
| 209 | + |
| 210 | +## File Organization |
| 211 | + |
| 212 | +### Directory Structure |
| 213 | +``` |
| 214 | +/ |
| 215 | +├── src/ # Source code |
| 216 | +│ ├── cli/ # CLI-specific classes |
| 217 | +│ ├── exceptions/ # Custom exceptions |
| 218 | +│ └── views/ # View classes |
| 219 | +├── test/ # Test files |
| 220 | +├── public/ # Public web root |
| 221 | +├── linter/ # Linting configuration |
| 222 | +└── .cursor/ # Cursor AI rules |
| 223 | + └── rules/ # This file |
| 224 | +``` |
| 225 | + |
| 226 | +## Security Practices |
| 227 | + |
| 228 | +1. **Always escape shell commands** - Use `escapeshellcmd()` carefully |
| 229 | +2. **Validate all inputs** - Check repo names, keys, etc. |
| 230 | +3. **Use whitelisting** - For IPs, allowed strings, etc. |
| 231 | +4. **Never expose secrets** - Mask in logs and output |
| 232 | +5. **Parameterize dangerous operations** - SQL, shell commands |
| 233 | + |
| 234 | +## Best Practices |
| 235 | + |
| 236 | +1. **Type Hints**: Always use type hints for better IDE support and type safety |
| 237 | +2. **Dependency Injection**: Inject dependencies via constructor |
| 238 | +3. **Single Responsibility**: Each class should have one clear purpose |
| 239 | +4. **Immutability**: Prefer readonly properties when possible |
| 240 | +5. **Error Handling**: Use custom exceptions, not generic ones |
| 241 | +6. **Logging**: Log important operations and errors |
| 242 | +7. **Testing**: Write tests BEFORE implementing features (TDD) |
| 243 | + |
| 244 | +## Pre-commit Checklist |
| 245 | + |
| 246 | +Before committing code: |
| 247 | +- [ ] Run `./linter/lint.sh` and ensure no errors |
| 248 | +- [ ] Run `composer run-script test` and ensure all tests pass |
| 249 | +- [ ] Update tests if adding new functionality |
| 250 | +- [ ] Update documentation if changing public APIs |
| 251 | +- [ ] Follow commit message format |
| 252 | +- [ ] No debug code or commented-out code |
| 253 | +- [ ] No trailing whitespace or whitespace in blank lines |
| 254 | + |
0 commit comments