Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 08:43:22 +08:00
commit aab6ef2415
31 changed files with 12720 additions and 0 deletions

180
scripts/check-architecture.sh Executable file
View File

@@ -0,0 +1,180 @@
#!/usr/bin/env bash
#
# TYPO3 PHP Architecture Conformance Checker
#
# Validates dependency injection, services, events, and architectural patterns
#
set -e
PROJECT_DIR="${1:-.}"
cd "${PROJECT_DIR}"
echo "## 3. PHP Architecture Conformance"
echo ""
has_issues=0
### Check for Services.yaml
echo "### Dependency Injection Configuration"
echo ""
if [ -f "Configuration/Services.yaml" ]; then
echo "- ✅ Configuration/Services.yaml present"
# Check if it has basic DI configuration
if grep -q "autowire: true" Configuration/Services.yaml; then
echo " - ✅ Autowiring enabled"
else
echo " - ⚠️ Autowiring not enabled"
fi
if grep -q "autoconfigure: true" Configuration/Services.yaml; then
echo " - ✅ Autoconfiguration enabled"
else
echo " - ⚠️ Autoconfiguration not enabled"
fi
else
echo "- ❌ Configuration/Services.yaml missing (CRITICAL)"
has_issues=1
fi
### Check for deprecated patterns
echo ""
echo "### Deprecated Pattern Detection"
echo ""
# Check for GeneralUtility::makeInstance
makeinstance_count=$(grep -r "GeneralUtility::makeInstance" Classes/ 2>/dev/null | wc -l)
if [ $makeinstance_count -eq 0 ]; then
echo "- ✅ No GeneralUtility::makeInstance() usage found"
else
echo "- ❌ ${makeinstance_count} instances of GeneralUtility::makeInstance() found"
echo " - Should use constructor injection instead"
has_issues=1
fi
# Check for global state access
globals_count=$(grep -r '\$GLOBALS\[' Classes/ 2>/dev/null | wc -l)
if [ $globals_count -eq 0 ]; then
echo "- ✅ No \$GLOBALS access found"
else
echo "- ❌ ${globals_count} instances of \$GLOBALS access found"
echo " - Should use dependency injection instead"
has_issues=1
fi
### Check for constructor injection
echo ""
echo "### Dependency Injection Patterns"
echo ""
# Check for constructors with dependencies
constructors=$(grep -r "public function __construct" Classes/ 2>/dev/null | wc -l)
if [ $constructors -gt 0 ]; then
echo "- ✅ ${constructors} classes use constructors (potential DI)"
else
echo "- ⚠️ No constructor injection found"
fi
# Check for method injection (inject* methods)
inject_methods=$(grep -r "public function inject[A-Z]" Classes/ 2>/dev/null | wc -l)
if [ $inject_methods -gt 0 ]; then
echo "- ⚠️ ${inject_methods} method injection patterns found (inject*)"
echo " - Consider using constructor injection instead (more modern)"
fi
### Check for PSR-14 events
echo ""
echo "### Event System"
echo ""
# Check for event classes
event_classes=$(find Classes/ -type d -name "Event" 2>/dev/null || echo "")
if [ -n "$event_classes" ]; then
event_count=$(find Classes/ -path "*/Event/*.php" 2>/dev/null | wc -l)
echo "- ✅ ${event_count} event classes found in Classes/Event/"
else
echo "- ⚠️ No Classes/Event/ directory found"
fi
# Check for event listeners
listener_classes=$(find Classes/ -type d -name "EventListener" 2>/dev/null || echo "")
if [ -n "$listener_classes" ]; then
listener_count=$(find Classes/ -path "*/EventListener/*.php" 2>/dev/null | wc -l)
echo "- ✅ ${listener_count} event listeners found in Classes/EventListener/"
else
echo "- ⚠️ No Classes/EventListener/ directory found"
fi
### Check for Extbase patterns
echo ""
echo "### Extbase Architecture"
echo ""
# Check for domain models
if [ -d "Classes/Domain/Model" ]; then
model_count=$(find Classes/Domain/Model/ -name "*.php" 2>/dev/null | wc -l)
echo "- ✅ ${model_count} domain models found"
else
echo "- No Classes/Domain/Model/ (not using Extbase models)"
fi
# Check for repositories
if [ -d "Classes/Domain/Repository" ]; then
repo_count=$(find Classes/Domain/Repository/ -name "*.php" 2>/dev/null | wc -l)
echo "- ✅ ${repo_count} repositories found"
# Check if repositories extend Repository
proper_repos=$(grep -r "extends.*Repository" Classes/Domain/Repository/ 2>/dev/null | wc -l)
if [ $proper_repos -gt 0 ]; then
echo " - ✅ Repositories extend base Repository class"
fi
else
echo "- No Classes/Domain/Repository/ (not using Extbase repositories)"
fi
# Check for controllers
if [ -d "Classes/Controller" ]; then
controller_count=$(find Classes/Controller/ -name "*.php" 2>/dev/null | wc -l)
echo "- ✅ ${controller_count} controllers found"
# Check if controllers extend ActionController
proper_controllers=$(grep -r "extends ActionController" Classes/Controller/ 2>/dev/null | wc -l)
if [ $proper_controllers -gt 0 ]; then
echo " - ✅ Controllers extend ActionController"
fi
fi
### Check for PSR-15 middleware
echo ""
echo "### Middleware"
echo ""
if [ -f "Configuration/RequestMiddlewares.php" ]; then
echo "- ✅ Configuration/RequestMiddlewares.php present"
middleware_count=$(find Classes/ -path "*/Middleware/*.php" 2>/dev/null | wc -l)
if [ $middleware_count -gt 0 ]; then
echo " - ✅ ${middleware_count} middleware classes found"
fi
else
echo "- No Configuration/RequestMiddlewares.php (not using custom middleware)"
fi
echo ""
echo "### Summary"
echo ""
if [ $has_issues -eq 0 ]; then
echo "- ✅ **PHP Architecture: PASSED**"
else
echo "- ⚠️ **PHP Architecture: ISSUES FOUND**"
fi
echo ""
echo "---"
echo ""
exit $has_issues

168
scripts/check-coding-standards.sh Executable file
View File

@@ -0,0 +1,168 @@
#!/usr/bin/env bash
#
# TYPO3 Coding Standards Conformance Checker
#
# Validates PSR-12 compliance and TYPO3-specific code style
#
set -e
PROJECT_DIR="${1:-.}"
cd "${PROJECT_DIR}"
echo "## 2. Coding Standards Conformance"
echo ""
has_issues=0
# Find all PHP files in Classes/
if [ ! -d "Classes" ]; then
echo "- ❌ Classes/ directory not found"
echo ""
echo "---"
echo ""
exit 1
fi
php_files=$(find Classes/ -name "*.php" 2>/dev/null || echo "")
if [ -z "$php_files" ]; then
echo "- ⚠️ No PHP files found in Classes/"
echo ""
echo "---"
echo ""
exit 0
fi
total_files=$(echo "$php_files" | wc -l)
echo "**Total PHP files:** $total_files"
echo ""
### Check for strict types
echo "### Strict Types Declaration"
echo ""
missing_strict=0
for file in $php_files; do
if ! grep -q "declare(strict_types=1)" "$file"; then
missing_strict=$((missing_strict + 1))
fi
done
if [ $missing_strict -eq 0 ]; then
echo "- ✅ All files have declare(strict_types=1)"
else
echo "- ❌ ${missing_strict} files missing declare(strict_types=1)"
has_issues=1
fi
### Check for old array syntax
echo ""
echo "### Array Syntax"
echo ""
old_array_count=$(grep -r "array(" Classes/ 2>/dev/null | wc -l)
if [ $old_array_count -eq 0 ]; then
echo "- ✅ No old array() syntax found"
else
echo "- ❌ ${old_array_count} instances of old array() syntax (should use [])"
has_issues=1
fi
### Check for proper namespace
echo ""
echo "### Namespace Structure"
echo ""
files_without_namespace=0
for file in $php_files; do
if ! grep -q "^namespace " "$file"; then
files_without_namespace=$((files_without_namespace + 1))
fi
done
if [ $files_without_namespace -eq 0 ]; then
echo "- ✅ All files have namespace declaration"
else
echo "- ❌ ${files_without_namespace} files missing namespace declaration"
has_issues=1
fi
### Check for PHPDoc comments on classes
echo ""
echo "### PHPDoc Comments"
echo ""
classes_without_doc=0
for file in $php_files; do
# Simple check: look for /** before class declaration
if grep -q "^class " "$file" || grep -q "^final class " "$file"; then
if ! grep -B 5 "^class \|^final class " "$file" | grep -q "/\*\*"; then
classes_without_doc=$((classes_without_doc + 1))
fi
fi
done
if [ $classes_without_doc -eq 0 ]; then
echo "- ✅ All classes have PHPDoc comments"
else
echo "- ⚠️ ${classes_without_doc} classes missing PHPDoc comments"
fi
### Check naming conventions
echo ""
echo "### Naming Conventions"
echo ""
# Check for snake_case in class names (should be UpperCamelCase)
snake_case_classes=$(grep -rE "^(final )?class [a-z][a-z0-9_]*" Classes/ 2>/dev/null | wc -l)
if [ $snake_case_classes -gt 0 ]; then
echo "- ❌ ${snake_case_classes} classes using incorrect naming (should be UpperCamelCase)"
has_issues=1
else
echo "- ✅ Class naming follows UpperCamelCase convention"
fi
### Check for tabs instead of spaces
echo ""
echo "### Indentation"
echo ""
files_with_tabs=0
for file in $php_files; do
if grep -qP "\t" "$file"; then
files_with_tabs=$((files_with_tabs + 1))
fi
done
if [ $files_with_tabs -eq 0 ]; then
echo "- ✅ No tabs found (using spaces for indentation)"
else
echo "- ❌ ${files_with_tabs} files using tabs instead of spaces"
has_issues=1
fi
### Check for proper use statements
echo ""
echo "### Use Statements"
echo ""
# Check if use statements are present and not duplicated
duplicate_uses=$(grep -rh "^use " Classes/ 2>/dev/null | sort | uniq -d | wc -l)
if [ $duplicate_uses -gt 0 ]; then
echo "- ⚠️ ${duplicate_uses} duplicate use statements found"
else
echo "- ✅ No duplicate use statements"
fi
echo ""
echo "### Summary"
echo ""
if [ $has_issues -eq 0 ]; then
echo "- ✅ **Coding standards: PASSED**"
else
echo "- ⚠️ **Coding standards: ISSUES FOUND**"
fi
echo ""
echo "---"
echo ""
exit $has_issues

197
scripts/check-conformance.sh Executable file
View File

@@ -0,0 +1,197 @@
#!/usr/bin/env bash
#
# TYPO3 Extension Conformance Checker
#
# Main script to orchestrate all conformance checks
#
set -e
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# Configuration
PROJECT_DIR="${1:-.}"
REPORT_DIR="${PROJECT_DIR}/.conformance-reports"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
REPORT_FILE="${REPORT_DIR}/conformance_${TIMESTAMP}.md"
# Script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
echo -e "${BLUE}╔════════════════════════════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ TYPO3 Extension Conformance Checker ║${NC}"
echo -e "${BLUE}╚════════════════════════════════════════════════════════════╝${NC}"
echo ""
echo -e "${BLUE}Standards Compliance Check:${NC}"
echo -e " • TYPO3 Version: ${YELLOW}12.4 LTS / 13.x${NC}"
echo -e " • PHP Version: ${YELLOW}8.1 / 8.2 / 8.3 / 8.4${NC}"
echo -e " • PSR Standard: ${YELLOW}PSR-12 (Extended Coding Style)${NC}"
echo -e " • Architecture: ${YELLOW}Dependency Injection, PSR-14 Events${NC}"
echo ""
# Create report directory
mkdir -p "${REPORT_DIR}"
# Check if directory exists
if [ ! -d "${PROJECT_DIR}" ]; then
echo -e "${RED}✗ Error: Directory ${PROJECT_DIR} not found${NC}"
exit 1
fi
cd "${PROJECT_DIR}"
# Check if this is a TYPO3 extension
if [ ! -f "composer.json" ] && [ ! -f "ext_emconf.php" ]; then
echo -e "${RED}✗ Error: Not a TYPO3 extension (composer.json or ext_emconf.php not found)${NC}"
exit 1
fi
echo -e "${GREEN}✓ TYPO3 Extension detected${NC}"
echo ""
# Initialize report
cat > "${REPORT_FILE}" <<'EOF'
# TYPO3 Extension Conformance Report
**Generated:** $(date -u +"%Y-%m-%d %H:%M:%S UTC")
**Project:** $(basename "$(pwd)")
## Standards Checked
This conformance check validates your extension against the following standards:
| Standard | Version/Specification |
|----------|----------------------|
| **TYPO3 Core** | 12.4 LTS / 13.x |
| **PHP** | 8.1 / 8.2 / 8.3 / 8.4 |
| **Coding Style** | PSR-12 (Extended Coding Style) |
| **Architecture** | Dependency Injection (PSR-11), PSR-14 Events, PSR-15 Middleware |
| **Testing** | PHPUnit 10+, TYPO3 Testing Framework |
| **Documentation** | reStructuredText (RST), TYPO3 Documentation Standards |
**Reference Documentation:**
- [TYPO3 Extension Architecture](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ExtensionArchitecture/)
- [TYPO3 Coding Guidelines](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/CodingGuidelines/)
- [PHP Architecture](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/PhpArchitecture/)
- [Testing Standards](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/Testing/)
---
## Summary
| Category | Score | Status |
|----------|-------|--------|
EOF
# Initialize scores
total_score=0
max_score=100
echo -e "${YELLOW}Running conformance checks...${NC}"
echo ""
# 1. File Structure Check
echo -e "${BLUE}[1/5] Checking file structure...${NC}"
if bash "${SCRIPT_DIR}/check-file-structure.sh" "${PROJECT_DIR}" >> "${REPORT_FILE}"; then
echo -e "${GREEN} ✓ File structure check complete${NC}"
structure_score=18
else
echo -e "${YELLOW} ⚠ File structure issues found${NC}"
structure_score=10
fi
echo ""
# 2. Coding Standards Check
echo -e "${BLUE}[2/5] Checking coding standards...${NC}"
if bash "${SCRIPT_DIR}/check-coding-standards.sh" "${PROJECT_DIR}" >> "${REPORT_FILE}"; then
echo -e "${GREEN} ✓ Coding standards check complete${NC}"
coding_score=18
else
echo -e "${YELLOW} ⚠ Coding standards issues found${NC}"
coding_score=12
fi
echo ""
# 3. Architecture Check
echo -e "${BLUE}[3/5] Checking PHP architecture...${NC}"
if bash "${SCRIPT_DIR}/check-architecture.sh" "${PROJECT_DIR}" >> "${REPORT_FILE}"; then
echo -e "${GREEN} ✓ Architecture check complete${NC}"
arch_score=18
else
echo -e "${YELLOW} ⚠ Architecture issues found${NC}"
arch_score=10
fi
echo ""
# 4. Testing Check
echo -e "${BLUE}[4/6] Checking testing infrastructure...${NC}"
if bash "${SCRIPT_DIR}/check-testing.sh" "${PROJECT_DIR}" >> "${REPORT_FILE}"; then
echo -e "${GREEN} ✓ Testing check complete${NC}"
test_score=16
else
echo -e "${YELLOW} ⚠ Testing issues found${NC}"
test_score=8
fi
echo ""
# 5. PHPStan Baseline Check
echo -e "${BLUE}[5/6] Checking PHPStan baseline hygiene...${NC}"
if bash "${SCRIPT_DIR}/check-phpstan-baseline.sh" "${PROJECT_DIR}"; then
echo -e "${GREEN} ✓ PHPStan baseline hygiene check passed${NC}"
baseline_score=10
else
echo -e "${RED} ✗ PHPStan baseline violation detected${NC}"
baseline_score=0
fi
echo ""
# 6. Generate comprehensive report
echo -e "${BLUE}[6/6] Generating final report...${NC}"
bash "${SCRIPT_DIR}/generate-report.sh" "${PROJECT_DIR}" "${REPORT_FILE}" \
"${structure_score}" "${coding_score}" "${arch_score}" "${test_score}"
echo ""
# Calculate total (including baseline hygiene score)
total_score=$((structure_score + coding_score + arch_score + test_score + baseline_score))
# Display summary
echo -e "${BLUE}╔════════════════════════════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ Conformance Results ║${NC}"
echo -e "${BLUE}╚════════════════════════════════════════════════════════════╝${NC}"
echo ""
echo -e " File Structure: ${structure_score}/20"
echo -e " Coding Standards: ${coding_score}/20"
echo -e " PHP Architecture: ${arch_score}/20"
echo -e " Testing Standards: ${test_score}/20"
echo -e " Baseline Hygiene: ${baseline_score}/10"
echo -e " Best Practices: 10/10"
echo ""
echo -e " ${BLUE}Total Score: ${total_score}/100${NC}"
echo ""
if [ ${total_score} -ge 80 ]; then
echo -e "${GREEN}✓ EXCELLENT conformance level${NC}"
elif [ ${total_score} -ge 60 ]; then
echo -e "${YELLOW}⚠ GOOD conformance level (some improvements recommended)${NC}"
elif [ ${total_score} -ge 40 ]; then
echo -e "${YELLOW}⚠ FAIR conformance level (several issues to address)${NC}"
else
echo -e "${RED}✗ POOR conformance level (major improvements needed)${NC}"
fi
echo ""
echo -e "${GREEN}Report saved to: ${REPORT_FILE}${NC}"
echo ""
# Exit with appropriate code
if [ ${total_score} -ge 60 ]; then
exit 0
else
exit 1
fi

197
scripts/check-file-structure.sh Executable file
View File

@@ -0,0 +1,197 @@
#!/usr/bin/env bash
#
# TYPO3 File Structure Conformance Checker
#
# Validates extension directory structure and required files
#
set -e
PROJECT_DIR="${1:-.}"
cd "${PROJECT_DIR}"
echo "## 1. File Structure Conformance"
echo ""
# Track issues
has_issues=0
echo "### Required Files"
echo ""
# Check required files
if [ -f "composer.json" ]; then
echo "- ✅ composer.json present"
else
echo "- ❌ composer.json missing (CRITICAL)"
has_issues=1
fi
if [ -f "ext_emconf.php" ]; then
echo "- ✅ ext_emconf.php present"
else
echo "- ⚠️ ext_emconf.php missing (required for TER publication)"
fi
if [ -f "Documentation/Index.rst" ]; then
echo "- ✅ Documentation/Index.rst present"
else
echo "- ⚠️ Documentation/Index.rst missing (required for docs.typo3.org)"
fi
if [ -f "Documentation/Settings.cfg" ]; then
echo "- ✅ Documentation/Settings.cfg present"
else
echo "- ⚠️ Documentation/Settings.cfg missing (required for docs.typo3.org)"
fi
echo ""
echo "### Directory Structure"
echo ""
# Check core directories
if [ -d "Classes" ]; then
echo "- ✅ Classes/ directory present"
# Check for common subdirectories
if [ -d "Classes/Controller" ]; then
echo " - ✅ Classes/Controller/ found"
fi
if [ -d "Classes/Domain/Model" ]; then
echo " - ✅ Classes/Domain/Model/ found"
fi
if [ -d "Classes/Domain/Repository" ]; then
echo " - ✅ Classes/Domain/Repository/ found"
fi
else
echo "- ❌ Classes/ directory missing (CRITICAL)"
has_issues=1
fi
if [ -d "Configuration" ]; then
echo "- ✅ Configuration/ directory present"
if [ -d "Configuration/TCA" ]; then
echo " - ✅ Configuration/TCA/ found"
fi
if [ -f "Configuration/Services.yaml" ]; then
echo " - ✅ Configuration/Services.yaml found"
else
echo " - ⚠️ Configuration/Services.yaml missing (recommended)"
fi
if [ -d "Configuration/Backend" ]; then
echo " - ✅ Configuration/Backend/ found"
fi
else
echo "- ⚠️ Configuration/ directory missing"
fi
if [ -d "Resources" ]; then
echo "- ✅ Resources/ directory present"
if [ -d "Resources/Private" ] && [ -d "Resources/Public" ]; then
echo " - ✅ Resources/Private/ and Resources/Public/ properly separated"
else
echo " - ⚠️ Resources/ not properly separated into Private/ and Public/"
fi
else
echo "- ⚠️ Resources/ directory missing"
fi
if [ -d "Tests" ]; then
echo "- ✅ Tests/ directory present"
if [ -d "Tests/Unit" ]; then
echo " - ✅ Tests/Unit/ found"
else
echo " - ⚠️ Tests/Unit/ missing"
fi
if [ -d "Tests/Functional" ]; then
echo " - ✅ Tests/Functional/ found"
else
echo " - ⚠️ Tests/Functional/ missing"
fi
else
echo "- ⚠️ Tests/ directory missing"
fi
echo ""
echo "### Anti-Patterns Check"
echo ""
# Check for PHP files in root (except ext_* files)
# Show all files but distinguish between tracked (issues) and untracked (info)
tracked_files=()
untracked_files=()
all_root_php_files=()
# Find all PHP files in root (except ext_* files)
while IFS= read -r file; do
filename=$(basename "$file")
if [[ "$filename" != ext_*.php ]]; then
all_root_php_files+=("$filename")
fi
done < <(find . -maxdepth 1 -name "*.php" 2>/dev/null || true)
# Check if files are tracked in git (if git repository exists)
if [ -d ".git" ]; then
for file in "${all_root_php_files[@]}"; do
if git ls-files --error-unmatch "$file" >/dev/null 2>&1; then
tracked_files+=("$file")
else
untracked_files+=("$file")
fi
done
else
# No git repository - treat all files as tracked (potential issues)
tracked_files=("${all_root_php_files[@]}")
fi
# Report tracked files (these are issues)
if [ ${#tracked_files[@]} -gt 0 ]; then
if [ -d ".git" ]; then
echo "- ❌ ${#tracked_files[@]} PHP file(s) in root directory committed to repository:"
else
echo "- ❌ ${#tracked_files[@]} PHP file(s) found in root directory:"
fi
for file in "${tracked_files[@]}"; do
echo " - ${file} (ISSUE: should be in Classes/ or Build/)"
done
has_issues=1
fi
# Report untracked files (informational only)
if [ ${#untracked_files[@]} -gt 0 ]; then
echo "- ${#untracked_files[@]} untracked PHP file(s) in root (ignored, not committed):"
for file in "${untracked_files[@]}"; do
echo " - ${file} (local file, not in repository)"
done
fi
# Success message if no files found
if [ ${#all_root_php_files[@]} -eq 0 ]; then
echo "- ✅ No PHP files in root (except ext_* files)"
fi
# Check for deprecated ext_tables.php
if [ -f "ext_tables.php" ]; then
echo "- ⚠️ ext_tables.php present (consider migrating to Configuration/Backend/)"
fi
# Check for wrong directory naming
if [ -d "Classes/Controllers" ]; then
echo "- ❌ Classes/Controllers/ found (should be Controller/ singular)"
has_issues=1
fi
if [ -d "Classes/Helpers" ]; then
echo "- ⚠️ Classes/Helpers/ found (should use Utility/ instead)"
fi
echo ""
echo "---"
echo ""
# Return appropriate exit code
if [ ${has_issues} -eq 0 ]; then
exit 0
else
exit 1
fi

110
scripts/check-phpstan-baseline.sh Executable file
View File

@@ -0,0 +1,110 @@
#!/usr/bin/env bash
# TYPO3 Extension Conformance Checker - PHPStan Baseline Validation
# Verifies that new code does not add errors to phpstan-baseline.neon
#
# Usage:
# ./check-phpstan-baseline.sh [path-to-extension]
#
# Returns:
# 0 = No baseline additions detected
# 1 = New errors added to baseline (violation)
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Parse arguments
PROJECT_ROOT="${1:-.}"
cd "$PROJECT_ROOT" || exit 1
echo "Checking PHPStan baseline hygiene in: $PROJECT_ROOT"
echo
# Check if git repository
if [ ! -d ".git" ]; then
echo -e "${YELLOW}⚠️ Not a git repository - skipping baseline check${NC}"
exit 0
fi
# Find baseline file
BASELINE_FILE=""
for path in "Build/phpstan-baseline.neon" "phpstan-baseline.neon" ".phpstan/baseline.neon"; do
if [ -f "$path" ]; then
BASELINE_FILE="$path"
break
fi
done
if [ -z "$BASELINE_FILE" ]; then
echo -e "${GREEN}✅ No baseline file found - all code passes PHPStan level 10!${NC}"
exit 0
fi
echo "Found baseline file: $BASELINE_FILE"
echo
# Check if baseline is modified in current changes
if ! git diff --quiet "$BASELINE_FILE" 2>/dev/null; then
echo -e "${YELLOW}⚠️ Baseline file has uncommitted changes${NC}"
echo
# Extract error counts from diff
BEFORE_COUNT=$(git show "HEAD:$BASELINE_FILE" 2>/dev/null | grep -E "^\s+count:\s+[0-9]+" | head -1 | grep -oE "[0-9]+" || echo "0")
AFTER_COUNT=$(grep -E "^\s+count:\s+[0-9]+" "$BASELINE_FILE" | head -1 | grep -oE "[0-9]+" || echo "0")
if [ "$AFTER_COUNT" -gt "$BEFORE_COUNT" ]; then
ADDED=$((AFTER_COUNT - BEFORE_COUNT))
echo -e "${RED}❌ BASELINE VIOLATION DETECTED${NC}"
echo
echo "Error count increased: $BEFORE_COUNT$AFTER_COUNT (+$ADDED errors)"
echo
echo "New code added $ADDED errors to the baseline!"
echo
echo "The baseline exists only for legacy code."
echo "All new code MUST pass PHPStan level 10 without baseline suppression."
echo
echo -e "${YELLOW}How to fix:${NC}"
echo "1. Run: composer ci:php:stan"
echo "2. Review the new errors reported"
echo "3. Fix the underlying issues (see coding-guidelines.md for patterns)"
echo "4. Revert baseline changes: git checkout $BASELINE_FILE"
echo "5. Verify: composer ci:php:stan should pass with original baseline"
echo
exit 1
elif [ "$AFTER_COUNT" -lt "$BEFORE_COUNT" ]; then
REMOVED=$((BEFORE_COUNT - AFTER_COUNT))
echo -e "${GREEN}✅ Excellent! Baseline reduced by $REMOVED errors${NC}"
echo
echo "You fixed existing baseline issues - great work!"
echo
else
echo -e "${YELLOW}⚠️ Baseline modified but count unchanged${NC}"
echo
echo "Review the baseline diff to ensure changes are intentional:"
echo " git diff $BASELINE_FILE"
echo
fi
else
echo -e "${GREEN}✅ No changes to baseline file${NC}"
fi
# Check for baseline in staged changes
if git diff --cached --quiet "$BASELINE_FILE" 2>/dev/null; then
echo -e "${GREEN}✅ No baseline changes staged for commit${NC}"
else
echo
echo -e "${YELLOW}⚠️ Warning: Baseline file is staged for commit${NC}"
echo
echo "Review staged baseline changes:"
echo " git diff --cached $BASELINE_FILE"
echo
fi
echo
echo -e "${GREEN}✅ PHPStan baseline hygiene check passed${NC}"
exit 0

199
scripts/check-testing.sh Executable file
View File

@@ -0,0 +1,199 @@
#!/usr/bin/env bash
#
# TYPO3 Testing Standards Conformance Checker
#
# Validates testing infrastructure and test coverage
#
set -e
PROJECT_DIR="${1:-.}"
cd "${PROJECT_DIR}"
echo "## 4. Testing Standards Conformance"
echo ""
has_issues=0
### Check for Tests directory
echo "### Test Infrastructure"
echo ""
if [ ! -d "Tests" ]; then
echo "- ❌ Tests/ directory missing (CRITICAL)"
has_issues=1
echo ""
echo "---"
echo ""
exit 1
fi
echo "- ✅ Tests/ directory present"
### Check for PHPUnit configuration
echo ""
echo "### PHPUnit Configuration"
echo ""
if [ -f "Build/phpunit/UnitTests.xml" ] || [ -f "phpunit.xml" ]; then
echo "- ✅ Unit test configuration found"
else
echo "- ❌ No Unit test configuration (Build/phpunit/UnitTests.xml or phpunit.xml)"
has_issues=1
fi
if [ -f "Build/phpunit/FunctionalTests.xml" ]; then
echo "- ✅ Functional test configuration found"
else
echo "- ⚠️ No Functional test configuration (Build/phpunit/FunctionalTests.xml)"
fi
### Unit Tests
echo ""
echo "### Unit Tests"
echo ""
if [ -d "Tests/Unit" ]; then
unit_test_count=$(find Tests/Unit/ -name "*Test.php" 2>/dev/null | wc -l)
echo "- ✅ Tests/Unit/ directory present"
echo " - **${unit_test_count} unit test files found**"
if [ $unit_test_count -eq 0 ]; then
echo " - ⚠️ No unit tests found"
fi
# Check if tests mirror Classes structure
if [ -d "Classes/Controller" ] && [ ! -d "Tests/Unit/Controller" ]; then
echo " - ⚠️ Tests/Unit/Controller/ missing (Classes/Controller/ exists)"
fi
if [ -d "Classes/Service" ] && [ ! -d "Tests/Unit/Service" ]; then
echo " - ⚠️ Tests/Unit/Service/ missing (Classes/Service/ exists)"
fi
if [ -d "Classes/Domain/Repository" ] && [ ! -d "Tests/Unit/Domain/Repository" ]; then
echo " - ⚠️ Tests/Unit/Domain/Repository/ missing (Classes/Domain/Repository/ exists)"
fi
else
echo "- ❌ Tests/Unit/ directory missing"
has_issues=1
fi
### Functional Tests
echo ""
echo "### Functional Tests"
echo ""
if [ -d "Tests/Functional" ]; then
func_test_count=$(find Tests/Functional/ -name "*Test.php" 2>/dev/null | wc -l)
echo "- ✅ Tests/Functional/ directory present"
echo " - **${func_test_count} functional test files found**"
# Check for fixtures
if [ -d "Tests/Functional/Fixtures" ]; then
fixture_count=$(find Tests/Functional/Fixtures/ -name "*.csv" -o -name "*.xml" 2>/dev/null | wc -l)
echo " - ✅ Tests/Functional/Fixtures/ found (${fixture_count} fixture files)"
else
if [ $func_test_count -gt 0 ]; then
echo " - ⚠️ No Tests/Functional/Fixtures/ (functional tests may need fixtures)"
fi
fi
else
echo "- ⚠️ Tests/Functional/ directory missing"
echo " - Functional tests recommended for repository and database operations"
fi
### Acceptance Tests
echo ""
echo "### Acceptance Tests"
echo ""
if [ -d "Tests/Acceptance" ]; then
accept_test_count=$(find Tests/Acceptance/ -name "*Cest.php" 2>/dev/null | wc -l)
echo "- ✅ Tests/Acceptance/ directory present"
echo " - **${accept_test_count} acceptance test files found**"
if [ -f "Tests/codeception.yml" ]; then
echo " - ✅ codeception.yml configuration found"
else
echo " - ⚠️ codeception.yml configuration missing"
fi
else
echo "- Tests/Acceptance/ not found (optional for most extensions)"
fi
### Test Coverage Estimate
echo ""
echo "### Test Coverage Estimate"
echo ""
if [ -d "Classes" ]; then
class_count=$(find Classes/ -name "*.php" 2>/dev/null | wc -l)
if [ -d "Tests/Unit" ]; then
unit_count=$(find Tests/Unit/ -name "*Test.php" 2>/dev/null | wc -l)
else
unit_count=0
fi
if [ -d "Tests/Functional" ]; then
func_count=$(find Tests/Functional/ -name "*Test.php" 2>/dev/null | wc -l)
else
func_count=0
fi
total_tests=$((unit_count + func_count))
echo "- **Total Classes:** $class_count"
echo "- **Total Tests:** $total_tests"
if [ $class_count -gt 0 ]; then
coverage_ratio=$((total_tests * 100 / class_count))
echo "- **Test Ratio:** ${coverage_ratio}%"
if [ $coverage_ratio -ge 70 ]; then
echo " - ✅ Good test coverage (≥70%)"
elif [ $coverage_ratio -ge 50 ]; then
echo " - ⚠️ Moderate test coverage (50-70%)"
else
echo " - ❌ Low test coverage (<50%)"
has_issues=1
fi
fi
fi
### Check for testing framework dependency
echo ""
echo "### Testing Framework Dependency"
echo ""
if [ -f "composer.json" ]; then
if grep -q "typo3/testing-framework" composer.json; then
echo "- ✅ typo3/testing-framework in composer.json"
else
echo "- ⚠️ typo3/testing-framework not found in composer.json"
fi
if grep -q "phpunit/phpunit" composer.json; then
echo "- ✅ phpunit/phpunit in composer.json"
else
echo "- ⚠️ phpunit/phpunit not found in composer.json"
fi
fi
echo ""
echo "### Summary"
echo ""
if [ $has_issues -eq 0 ]; then
echo "- ✅ **Testing Standards: PASSED**"
else
echo "- ⚠️ **Testing Standards: ISSUES FOUND**"
fi
echo ""
echo "---"
echo ""
exit $has_issues

143
scripts/generate-report.sh Executable file
View File

@@ -0,0 +1,143 @@
#!/usr/bin/env bash
#
# Generate final conformance report with recommendations
#
set -e
PROJECT_DIR="${1}"
REPORT_FILE="${2}"
STRUCTURE_SCORE="${3:-15}"
CODING_SCORE="${4:-15}"
ARCH_SCORE="${5:-15}"
TEST_SCORE="${6:-15}"
cd "${PROJECT_DIR}"
# Calculate total
TOTAL_SCORE=$((STRUCTURE_SCORE + CODING_SCORE + ARCH_SCORE + TEST_SCORE + 10))
# Update summary table
sed -i "s/| Extension Architecture .*/| Extension Architecture | ${STRUCTURE_SCORE}\/20 | $(if [ ${STRUCTURE_SCORE} -ge 15 ]; then echo "✅ Passed"; else echo "⚠️ Issues"; fi) |/" "${REPORT_FILE}"
sed -i "/| Extension Architecture /a | Coding Guidelines | ${CODING_SCORE}/20 | $(if [ ${CODING_SCORE} -ge 15 ]; then echo "✅ Passed"; else echo "⚠️ Issues"; fi) |" "${REPORT_FILE}" 2>/dev/null || true
sed -i "/| Coding Guidelines /a | PHP Architecture | ${ARCH_SCORE}/20 | $(if [ ${ARCH_SCORE} -ge 15 ]; then echo "✅ Passed"; else echo "⚠️ Issues"; fi) |" "${REPORT_FILE}" 2>/dev/null || true
sed -i "/| PHP Architecture /a | Testing Standards | ${TEST_SCORE}/20 | $(if [ ${TEST_SCORE} -ge 15 ]; then echo "✅ Passed"; else echo "⚠️ Issues"; fi) |" "${REPORT_FILE}" 2>/dev/null || true
sed -i "/| Testing Standards /a | Best Practices | 10/20 | Partial |" "${REPORT_FILE}" 2>/dev/null || true
sed -i "/| Best Practices /a | **TOTAL** | **${TOTAL_SCORE}/100** | $(if [ ${TOTAL_SCORE} -ge 80 ]; then echo "✅ Excellent"; elif [ ${TOTAL_SCORE} -ge 60 ]; then echo "✅ Good"; else echo "⚠️ Fair"; fi) |" "${REPORT_FILE}" 2>/dev/null || true
# Add final sections
cat >> "${REPORT_FILE}" <<EOF
---
## 5. Best Practices Assessment
### Project Infrastructure
- **README.md:** $(if [ -f "README.md" ]; then echo "✅ Present"; else echo "❌ Missing"; fi)
- **LICENSE:** $(if [ -f "LICENSE" ]; then echo "✅ Present"; else echo "❌ Missing"; fi)
- **.editorconfig:** $(if [ -f ".editorconfig" ]; then echo "✅ Present"; else echo "⚠️ Missing"; fi)
- **.gitignore:** $(if [ -f ".gitignore" ]; then echo "✅ Present"; else echo "⚠️ Missing"; fi)
### Code Quality Tools
- **php-cs-fixer:** $(if [ -f ".php-cs-fixer.dist.php" ] || [ -f ".php-cs-fixer.php" ] || [ -f "Build/.php-cs-fixer.dist.php" ] || [ -f "Build/.php-cs-fixer.php" ]; then echo "✅ Configured"; else echo "⚠️ Not configured"; fi)
- **phpstan:** $(if [ -f "phpstan.neon" ] || [ -f "phpstan.neon.dist" ] || [ -f "Build/phpstan.neon" ] || [ -f "Build/phpstan.neon.dist" ]; then echo "✅ Configured"; else echo "⚠️ Not configured"; fi)
- **rector:** $(if [ -f "rector.php" ] || [ -f "Build/rector.php" ]; then echo "✅ Configured"; else echo " Not configured"; fi)
### CI/CD Pipeline
- **GitHub Actions:** $(if [ -d ".github/workflows" ]; then echo "✅ Configured"; else echo "⚠️ Not found"; fi)
- **GitLab CI:** $(if [ -f ".gitlab-ci.yml" ]; then echo "✅ Configured"; else echo " Not found"; fi)
---
## Overall Assessment
**Total Score: ${TOTAL_SCORE}/100**
$(if [ ${TOTAL_SCORE} -ge 80 ]; then
cat <<END
### ✅ EXCELLENT Conformance Level
Your TYPO3 extension demonstrates strong adherence to official standards and best practices.
**Strengths:**
- Well-structured architecture following TYPO3 conventions
- Modern PHP patterns with dependency injection
- Good code quality and testing coverage
- Proper documentation and infrastructure
**Minor Improvements:**
- Continue maintaining high standards
- Keep dependencies updated
- Monitor code coverage trends
END
elif [ ${TOTAL_SCORE} -ge 60 ]; then
cat <<END
### ✅ GOOD Conformance Level
Your TYPO3 extension follows most standards with some areas for improvement.
**Next Steps:**
1. Address critical issues identified above
2. Improve test coverage
3. Add missing configuration files
4. Update deprecated patterns
**Timeline:** 2-4 weeks for improvements
END
else
cat <<END
### ⚠️ FAIR Conformance Level
Your TYPO3 extension requires significant improvements to meet TYPO3 standards.
**Priority Actions:**
1. Fix critical file structure issues
2. Migrate deprecated patterns (GeneralUtility::makeInstance, \$GLOBALS)
3. Add comprehensive testing infrastructure
4. Improve code quality (strict types, PHPDoc, PSR-12)
5. Add project infrastructure (CI/CD, quality tools)
**Timeline:** 4-8 weeks for comprehensive improvements
END
fi)
---
## Quick Action Checklist
### High Priority (Fix Now)
$(if [ ${STRUCTURE_SCORE} -lt 15 ]; then echo "- [ ] Fix critical file structure issues (missing required files/directories)"; fi)
$(if grep -q "GeneralUtility::makeInstance" Classes/ 2>/dev/null; then echo "- [ ] Migrate GeneralUtility::makeInstance to constructor injection"; fi)
$(if grep -q '\$GLOBALS\[' Classes/ 2>/dev/null; then echo "- [ ] Remove \$GLOBALS access, use dependency injection"; fi)
$(if [ ! -f "Configuration/Services.yaml" ]; then echo "- [ ] Add Configuration/Services.yaml with DI configuration"; fi)
### Medium Priority (Fix Soon)
$(if [ ${CODING_SCORE} -lt 15 ]; then echo "- [ ] Add declare(strict_types=1) to all PHP files"; fi)
$(if [ ${CODING_SCORE} -lt 15 ]; then echo "- [ ] Replace array() with [] short syntax"; fi)
$(if [ ${TEST_SCORE} -lt 15 ]; then echo "- [ ] Add unit tests for untested classes"; fi)
$(if [ ! -d "Tests/Functional" ]; then echo "- [ ] Add functional tests for repositories"; fi)
### Low Priority (Improve When Possible)
$(if [ ! -f ".php-cs-fixer.dist.php" ] && [ ! -f ".php-cs-fixer.php" ] && [ ! -f "Build/.php-cs-fixer.dist.php" ] && [ ! -f "Build/.php-cs-fixer.php" ]; then echo "- [ ] Configure PHP CS Fixer"; fi)
$(if [ ! -f "phpstan.neon" ] && [ ! -f "phpstan.neon.dist" ] && [ ! -f "Build/phpstan.neon" ] && [ ! -f "Build/phpstan.neon.dist" ]; then echo "- [ ] Configure PHPStan for static analysis"; fi)
$(if [ ! -d ".github/workflows" ]; then echo "- [ ] Set up CI/CD pipeline (GitHub Actions)"; fi)
- [ ] Improve PHPDoc comments coverage
- [ ] Add .editorconfig for consistent formatting
---
## Resources
- **TYPO3 Extension Architecture:** https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ExtensionArchitecture/
- **Coding Guidelines:** https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/CodingGuidelines/
- **Dependency Injection:** https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/DependencyInjection/
- **Testing Documentation:** https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/Testing/
- **Tea Extension (Best Practice):** https://github.com/TYPO3BestPractices/tea
---
*Report generated by TYPO3 Extension Conformance Checker*
EOF
echo "Final report generated successfully"