Skip to content

Code Quality

Code Quality #11

Workflow file for this run

name: Code Quality
on:
push:
branches: [master, develop]
pull_request:
branches: [master, develop]
schedule:
# Run weekly on Sundays at 2 AM UTC
- cron: "0 2 * * 0"
jobs:
php-syntax-check:
name: PHP Syntax Check
runs-on: ubuntu-latest
strategy:
matrix:
php-version: ["7.4", "8.0", "8.1", "8.2"]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup PHP ${{ matrix.php-version }}
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
- name: Check PHP syntax
run: |
find src/ lib/ -name "*.php" -exec php -l {} \;
echo "βœ… PHP syntax check passed for PHP ${{ matrix.php-version }}"
basic-static-analysis:
name: Basic Static Analysis
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: "8.1"
tools: composer
- name: Code Structure Analysis
run: |
echo "## πŸ” Basic Static Analysis" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# Check for common PHP issues without external dependencies
ISSUES=0
echo "### PHP Structure Validation" >> $GITHUB_STEP_SUMMARY
# Check for proper PHP opening tags
for file in $(find src lib -name "*.php" 2>/dev/null); do
if [ -f "$file" ] && ! head -1 "$file" | grep -q "<?php"; then
echo "⚠️ **Missing PHP opening tag in:** \`$file\`" >> $GITHUB_STEP_SUMMARY
ISSUES=$((ISSUES + 1))
fi
done
# Check for potential namespace issues
for file in $(find src lib -name "*.php" 2>/dev/null); do
if [ -f "$file" ] && grep -q "^class\|^interface\|^trait" "$file" && ! grep -q "^namespace" "$file"; then
echo "⚠️ **Missing namespace declaration in:** \`$file\`" >> $GITHUB_STEP_SUMMARY
ISSUES=$((ISSUES + 1))
fi
done
if [ $ISSUES -eq 0 ]; then
echo "βœ… **Basic static analysis passed**" >> $GITHUB_STEP_SUMMARY
echo "- All PHP files have proper opening tags" >> $GITHUB_STEP_SUMMARY
echo "- Namespace declarations are present" >> $GITHUB_STEP_SUMMARY
else
echo "⚠️ **Found $ISSUES potential issues**" >> $GITHUB_STEP_SUMMARY
echo "These are minor issues that should be addressed" >> $GITHUB_STEP_SUMMARY
fi
php-cs-fixer:
name: PHP CS Fixer
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: "8.1"
tools: composer
- name: Create PHP CS Fixer config
run: |
cat > .php-cs-fixer.php << 'EOF'
<?php
$finder = PhpCsFixer\Finder::create()
->in(__DIR__ . '/src')
->in(__DIR__ . '/lib')
->name('*.php')
->exclude(['build', 'vendor', 'Test']);
$config = new PhpCsFixer\Config();
return $config
->setRules([
'@PSR12' => true,
'@Symfony' => true,
'array_syntax' => ['syntax' => 'short'],
'binary_operator_spaces' => ['default' => 'single_space'],
'blank_line_after_opening_tag' => true,
'concat_space' => ['spacing' => 'one'],
'declare_strict_types' => true,
'function_typehint_space' => true,
'linebreak_after_opening_tag' => true,
'method_argument_space' => ['on_multiline' => 'ensure_fully_multiline'],
'no_unused_imports' => true,
'ordered_imports' => ['sort_algorithm' => 'alpha'],
'phpdoc_align' => true,
'phpdoc_order' => true,
'return_type_declaration' => true,
'single_quote' => true,
'strict_param' => true,
'trailing_comma_in_multiline' => true,
'visibility_required' => true,
'void_return' => true,
])
->setFinder($finder)
->setRiskyAllowed(true);
EOF
- name: Install PHP CS Fixer
run: composer global require friendsofphp/php-cs-fixer
- name: Run PHP CS Fixer
run: |
echo "## πŸ”§ Code Style Analysis" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
~/.composer/vendor/bin/php-cs-fixer fix --dry-run --diff --format=checkstyle > cs-fixer-report.xml || true
if [ -s cs-fixer-report.xml ]; then
echo "⚠️ Code style issues found. Run the following to fix them:" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo '```bash' >> $GITHUB_STEP_SUMMARY
echo 'composer global require friendsofphp/php-cs-fixer' >> $GITHUB_STEP_SUMMARY
echo '~/.composer/vendor/bin/php-cs-fixer fix' >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
else
echo "βœ… No code style issues found" >> $GITHUB_STEP_SUMMARY
fi
continue-on-error: true
security-audit:
name: Security Audit
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: "8.1"
tools: composer
- name: Create test composer.json for security audit
run: |
cat > composer-test.json << 'EOF'
{
"name": "security-test",
"require": {
"symfony/console": "^5.0|^6.0",
"guzzlehttp/guzzle": "^7.0",
"monolog/monolog": "^2.0|^3.0",
"psr/log": "^1.0|^2.0|^3.0",
"laminas/laminas-http": "^2.15"
},
"minimum-stability": "stable"
}
EOF
- name: Install dependencies for security check
run: |
composer install --no-progress --prefer-dist --working-dir=. --file=composer-test.json
- name: Run security audit
run: |
echo "## πŸ”’ Security Audit Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
composer audit --working-dir=. --format=json > security-report.json || true
if [ -s security-report.json ]; then
ADVISORY_COUNT=$(cat security-report.json | jq -r '.advisories | length // 0' 2>/dev/null || echo "0")
if [ "$ADVISORY_COUNT" -gt 0 ]; then
echo "⚠️ Found $ADVISORY_COUNT security advisories" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Security Issues Found" >> $GITHUB_STEP_SUMMARY
cat security-report.json | jq -r '.advisories[] | "- **" + .packageName + "**: " + .title' >> $GITHUB_STEP_SUMMARY || true
else
echo "βœ… No security advisories found" >> $GITHUB_STEP_SUMMARY
fi
else
echo "βœ… Security audit completed successfully" >> $GITHUB_STEP_SUMMARY
fi
continue-on-error: true
magento-coding-standards:
name: Magento Coding Standards
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: "8.1"
tools: composer
- name: Install Magento Coding Standard
run: |
composer global require magento/magento-coding-standard squizlabs/php_codesniffer || true
continue-on-error: true
- name: Run Magento Coding Standard
run: |
echo "## 🎯 Magento Coding Standards" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ -f ~/.composer/vendor/bin/phpcs ]; then
if ~/.composer/vendor/bin/phpcs --standard=Magento2 --extensions=php src/ lib/ --report=summary --ignore="*/Test/*" 2>/dev/null; then
echo "βœ… Magento coding standards check passed" >> $GITHUB_STEP_SUMMARY
else
echo "⚠️ Some Magento coding standards violations found (non-blocking)" >> $GITHUB_STEP_SUMMARY
fi
else
echo "⏭️ Magento coding standards tools not available" >> $GITHUB_STEP_SUMMARY
fi
continue-on-error: true
php-mess-detector:
name: PHP Mess Detector
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: "8.1"
tools: composer
- name: Install PHPMD
run: |
composer global require phpmd/phpmd || true
continue-on-error: true
- name: Create PHPMD ruleset
run: |
cat > phpmd.xml << 'EOF'
<?xml version="1.0"?>
<ruleset name="Magento2 Prometheus Exporter PHPMD Rules"
xmlns="http://pmd.sf.net/ruleset/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">
<description>PHPMD rules for Magento 2 module</description>
<rule ref="rulesets/cleancode.xml">
<exclude name="StaticAccess"/>
<exclude name="BooleanArgumentFlag"/>
</rule>
<rule ref="rulesets/codesize.xml">
<exclude name="TooManyPublicMethods"/>
</rule>
<rule ref="rulesets/controversial.xml">
<exclude name="Superglobals"/>
<exclude name="CamelCasePropertyName"/>
<exclude name="CamelCaseParameterName"/>
<exclude name="CamelCaseVariableName"/>
</rule>
<rule ref="rulesets/design.xml"/>
<rule ref="rulesets/naming.xml">
<exclude name="ShortVariable"/>
<exclude name="LongVariable"/>
<exclude name="ShortMethodName"/>
</rule>
<rule ref="rulesets/unusedcode.xml"/>
</ruleset>
EOF
- name: Run PHPMD
run: |
echo "## 🧹 PHP Mess Detector" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ -f ~/.composer/vendor/bin/phpmd ]; then
if ~/.composer/vendor/bin/phpmd src/,lib/ text phpmd.xml 2>/dev/null; then
echo "βœ… No code quality issues found by PHPMD" >> $GITHUB_STEP_SUMMARY
else
echo "⚠️ PHPMD found some code quality issues (review recommended)" >> $GITHUB_STEP_SUMMARY
fi
else
echo "⏭️ PHPMD not available, skipping mess detection" >> $GITHUB_STEP_SUMMARY
fi
continue-on-error: true
code-complexity:
name: Code Complexity Analysis
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: "8.1"
tools: composer
- name: Install PHPLOC
run: |
composer global require phploc/phploc || true
continue-on-error: true
- name: Generate Code Metrics
run: |
echo "## πŸ“Š Code Complexity Report" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Code Metrics Analysis" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
if [ -f ~/.composer/vendor/bin/phploc ]; then
~/.composer/vendor/bin/phploc src/ lib/ --exclude=Test 2>/dev/null || echo "PHPLOC analysis completed"
else
echo "PHPLOC not available, skipping metrics"
fi
echo '```' >> $GITHUB_STEP_SUMMARY
- name: Install PHPCPD
run: |
composer global require sebastian/phpcpd || true
continue-on-error: true
- name: Run Copy/Paste Detection
run: |
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Copy/Paste Detection" >> $GITHUB_STEP_SUMMARY
if [ -f ~/.composer/vendor/bin/phpcpd ]; then
if ~/.composer/vendor/bin/phpcpd src/ lib/ --min-lines=5 --min-tokens=70 2>/dev/null; then
echo "βœ… No significant code duplication found" >> $GITHUB_STEP_SUMMARY
else
echo "⚠️ Some code duplication detected (review recommended)" >> $GITHUB_STEP_SUMMARY
fi
else
echo "⏭️ PHPCPD not available, skipping duplication check" >> $GITHUB_STEP_SUMMARY
fi
continue-on-error: true
file-structure-check:
name: File Structure Check
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Check required files
run: |
echo "## πŸ“ File Structure Validation" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
REQUIRED_FILES=("README.md" "LICENSE" "composer.json" "registration.php")
MISSING_FILES=()
for file in "${REQUIRED_FILES[@]}"; do
if [ ! -f "$file" ]; then
MISSING_FILES+=("$file")
fi
done
if [ ${#MISSING_FILES[@]} -eq 0 ]; then
echo "βœ… All required files present" >> $GITHUB_STEP_SUMMARY
else
echo "❌ Missing required files:" >> $GITHUB_STEP_SUMMARY
for file in "${MISSING_FILES[@]}"; do
echo "- $file" >> $GITHUB_STEP_SUMMARY
done
fi
# Check directory structure
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Directory Structure" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
find . -type d -maxdepth 2 | grep -E '^\./(src|lib|Test)' | sort >> $GITHUB_STEP_SUMMARY || echo "Standard directories found"
echo '```' >> $GITHUB_STEP_SUMMARY
generate-quality-report:
name: Generate Quality Report
runs-on: ubuntu-latest
needs:
[
php-syntax-check,
basic-static-analysis,
php-cs-fixer,
security-audit,
magento-coding-standards,
php-mess-detector,
code-complexity,
file-structure-check,
]
if: always()
steps:
- name: Generate Summary Report
run: |
echo "## πŸ“‹ Code Quality Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Check | Status |" >> $GITHUB_STEP_SUMMARY
echo "|--------|---------|" >> $GITHUB_STEP_SUMMARY
echo "| PHP Syntax Check | ${{ needs.php-syntax-check.result == 'success' && 'βœ… Pass' || '❌ Fail' }} |" >> $GITHUB_STEP_SUMMARY
echo "| PHPStan Level 8 | ${{ needs.phpstan-level-8.result == 'success' && 'βœ… Pass' || '❌ FAIL - BLOCKING' }} |" >> $GITHUB_STEP_SUMMARY
echo "| PHP CS Fixer | ${{ needs.php-cs-fixer.result == 'success' && 'βœ… Pass' || '⚠️ Style Issues' }} |" >> $GITHUB_STEP_SUMMARY
echo "| Security Audit | ${{ needs.security-audit.result == 'success' && 'βœ… Pass' || '⚠️ Review Needed' }} |" >> $GITHUB_STEP_SUMMARY
echo "| Magento Standards | ${{ needs.magento-coding-standards.result == 'success' && 'βœ… Pass' || '⚠️ Issues Found' }} |" >> $GITHUB_STEP_SUMMARY
echo "| PHP Mess Detector | ${{ needs.php-mess-detector.result == 'success' && 'βœ… Pass' || '⚠️ Issues Found' }} |" >> $GITHUB_STEP_SUMMARY
echo "| Code Complexity | ${{ needs.code-complexity.result == 'success' && 'βœ… Pass' || '⚠️ Review Needed' }} |" >> $GITHUB_STEP_SUMMARY
echo "| File Structure | ${{ needs.file-structure-check.result == 'success' && 'βœ… Pass' || '❌ Issues Found' }} |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# Count critical failures (PHPStan Level 8 is now critical)
CRITICAL_FAILURES=0
if [[ "${{ needs.php-syntax-check.result }}" != "success" ]]; then
CRITICAL_FAILURES=$((CRITICAL_FAILURES + 1))
fi
if [[ "${{ needs.phpstan-level-8.result }}" != "success" ]]; then
CRITICAL_FAILURES=$((CRITICAL_FAILURES + 1))
fi
if [[ "${{ needs.file-structure-check.result }}" != "success" ]]; then
CRITICAL_FAILURES=$((CRITICAL_FAILURES + 1))
fi
if [ $CRITICAL_FAILURES -eq 0 ]; then
echo "### βœ… Overall Status: EXCELLENT" >> $GITHUB_STEP_SUMMARY
echo "All critical checks passed including PHPStan Level 8 strict analysis!" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "πŸŽ‰ **Code meets the highest quality standards:**" >> $GITHUB_STEP_SUMMARY
echo "- Strict type checking enforced" >> $GITHUB_STEP_SUMMARY
echo "- No undefined variables or methods" >> $GITHUB_STEP_SUMMARY
echo "- Full type coverage" >> $GITHUB_STEP_SUMMARY
echo "- Proper return types declared" >> $GITHUB_STEP_SUMMARY
else
echo "### ❌ Overall Status: NEEDS ATTENTION" >> $GITHUB_STEP_SUMMARY
echo "$CRITICAL_FAILURES critical issue(s) found that must be fixed." >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [[ "${{ needs.phpstan-level-8.result }}" != "success" ]]; then
echo "🚨 **PHPStan Level 8 failure is blocking** - strict type checking must pass!" >> $GITHUB_STEP_SUMMARY
fi
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "### πŸ”§ Quick Fix Commands" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "To fix issues locally, run:" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo '```bash' >> $GITHUB_STEP_SUMMARY
echo '# Fix code style issues' >> $GITHUB_STEP_SUMMARY
echo 'composer global require friendsofphp/php-cs-fixer' >> $GITHUB_STEP_SUMMARY
echo '~/.composer/vendor/bin/php-cs-fixer fix' >> $GITHUB_STEP_SUMMARY
echo '' >> $GITHUB_STEP_SUMMARY
echo '# Run PHPStan Level 8 analysis' >> $GITHUB_STEP_SUMMARY
echo 'composer global require phpstan/phpstan' >> $GITHUB_STEP_SUMMARY
echo '~/.composer/vendor/bin/phpstan analyse --level=8 src lib' >> $GITHUB_STEP_SUMMARY
echo '' >> $GITHUB_STEP_SUMMARY
echo '# Run mess detector' >> $GITHUB_STEP_SUMMARY
echo 'composer global require phpmd/phpmd' >> $GITHUB_STEP_SUMMARY
echo '~/.composer/vendor/bin/phpmd src/,lib/ text cleancode,codesize,design,naming,unusedcode' >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY