diff --git a/.gitignore b/.gitignore
index b1389f1..70000de 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,3 +20,9 @@ public/build
/coverage
/docs/.vitepress/dist
docs/.vitepress/cache/
+
+# QA tools
+.infection/
+infection.log
+infection-summary.log
+.rector-cache/
diff --git a/composer.json b/composer.json
index 0ac08ac..6bf2317 100644
--- a/composer.json
+++ b/composer.json
@@ -17,6 +17,7 @@
},
"require-dev": {
"fakerphp/faker": "^1.23",
+ "infection/infection": "^0.32.3",
"larastan/larastan": "^3.9",
"laravel/pint": "^1.18",
"mockery/mockery": "^1.6",
@@ -26,6 +27,9 @@
"phpstan/phpstan": "^2.1",
"phpstan/phpstan-deprecation-rules": "^2.0",
"phpunit/phpunit": "^11.5",
+ "psalm/plugin-laravel": "^3.0",
+ "rector/rector": "^2.3",
+ "roave/security-advisories": "dev-latest",
"spatie/laravel-activitylog": "^4.8",
"vimeo/psalm": "^6.14"
},
@@ -72,7 +76,8 @@
"sort-packages": true,
"allow-plugins": {
"php-http/discovery": true,
- "phpstan/extension-installer": true
+ "phpstan/extension-installer": true,
+ "infection/extension-installer": true
}
},
"minimum-stability": "stable",
diff --git a/infection.json5 b/infection.json5
new file mode 100644
index 0000000..5acb831
--- /dev/null
+++ b/infection.json5
@@ -0,0 +1,20 @@
+{
+ "$schema": "https://raw.githubusercontent.com/infection/infection/0.29.0/resources/schema.json",
+ "source": {
+ "directories": ["src"]
+ },
+ "logs": {
+ "text": "infection.log",
+ "summary": "infection-summary.log"
+ },
+ "mutators": {
+ "@default": true
+ },
+ "phpUnit": {
+ "configDir": "."
+ },
+ "testFramework": "phpunit",
+ "tmpDir": ".infection",
+ "minMsi": 50,
+ "minCoveredMsi": 70
+}
diff --git a/psalm.xml b/psalm.xml
index b4e4aff..1366687 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -8,6 +8,10 @@
findUnusedBaselineEntry="false"
findUnusedCode="false"
>
+
+
+
+
diff --git a/qa.yaml b/qa.yaml
new file mode 100644
index 0000000..86a463e
--- /dev/null
+++ b/qa.yaml
@@ -0,0 +1,107 @@
+# PHP Quality Assurance Pipeline
+# This file defines the QA process for `core php qa` command
+#
+# Usage: core php qa [--fix] [--full]
+# --fix Apply automatic fixes where possible
+# --full Run full suite including slow checks (mutation testing)
+
+name: PHP Quality Assurance
+version: 1.0.0
+
+# Tool versions and config files
+tools:
+ pint:
+ config: pint.json
+ description: Code style (PSR-12 + Laravel conventions)
+
+ phpstan:
+ config: phpstan.neon
+ level: 1
+ description: Static analysis (type checking)
+
+ psalm:
+ config: psalm.xml
+ level: 8
+ description: Static analysis (deeper type inference)
+
+ infection:
+ config: infection.json5
+ description: Mutation testing (test quality)
+
+ rector:
+ config: rector.php
+ description: Automated refactoring and upgrades
+
+# QA Pipeline stages
+stages:
+ # Stage 1: Quick checks (< 30 seconds)
+ quick:
+ - name: Security Audit
+ command: composer audit
+ description: Check dependencies for known vulnerabilities
+ fix: false
+
+ - name: Code Style
+ command: ./vendor/bin/pint --test
+ fix_command: ./vendor/bin/pint
+ description: Check PSR-12 and Laravel code style
+
+ - name: PHPStan
+ command: ./vendor/bin/phpstan analyse --no-progress
+ description: Static analysis level 1
+ fix: false
+
+ # Stage 2: Standard checks (< 2 minutes)
+ standard:
+ - name: Psalm
+ command: ./vendor/bin/psalm --no-progress
+ description: Deep static analysis
+ fix: false
+
+ - name: Tests
+ command: ./vendor/bin/phpunit --testdox
+ description: Run test suite
+ fix: false
+
+ # Stage 3: Full checks (can be slow)
+ full:
+ - name: Rector (dry-run)
+ command: ./vendor/bin/rector process --dry-run
+ fix_command: ./vendor/bin/rector process
+ description: Check for automated improvements
+
+ - name: Mutation Testing
+ command: ./vendor/bin/infection --min-msi=50 --min-covered-msi=70 --threads=4
+ description: Test suite quality via mutation testing
+ fix: false
+ slow: true
+
+# Exit codes
+exit_codes:
+ 0: All checks passed
+ 1: Code style issues (fixable)
+ 2: Static analysis errors
+ 3: Test failures
+ 4: Security vulnerabilities
+ 5: Mutation score too low
+
+# Recommended CI configuration
+ci:
+ # Run on every push
+ push:
+ - quick
+ - standard
+
+ # Run on PRs to main
+ pull_request:
+ - quick
+ - standard
+ - full
+
+# Thresholds
+thresholds:
+ phpstan_level: 1
+ psalm_level: 8
+ test_coverage: 70
+ mutation_msi: 50
+ mutation_covered_msi: 70
diff --git a/rector.php b/rector.php
new file mode 100644
index 0000000..a09b257
--- /dev/null
+++ b/rector.php
@@ -0,0 +1,38 @@
+withPaths([
+ __DIR__.'/src',
+ ])
+ ->withSkip([
+ __DIR__.'/src/Core/Activity',
+ __DIR__.'/src/Core/Tests',
+ __DIR__.'/src/Mod/Trees',
+ ])
+ ->withSets([
+ // PHP version upgrades
+ LevelSetList::UP_TO_PHP_82,
+
+ // Code quality
+ SetList::CODE_QUALITY,
+ SetList::CODING_STYLE,
+ SetList::DEAD_CODE,
+ SetList::EARLY_RETURN,
+ SetList::TYPE_DECLARATION,
+ ])
+ ->withImportNames(
+ importShortClasses: false,
+ removeUnusedImports: true
+ )
+ ->withPreparedSets(
+ deadCode: true,
+ codeQuality: true,
+ typeDeclarations: true,
+ earlyReturn: true,
+ );