name: Davidson CI on: push: pull_request: jobs: quality: runs-on: davidson-ci steps: - name: Checkout repository uses: actions/checkout@v4 - name: Detect project run: | echo "=== Project detection ===" PHP_COUNT=$(find . -type f -name "*.php" -not -path "./vendor/*" | wc -l) JS_COUNT=$(find . -type f \( -name "*.js" -o -name "*.mjs" -o -name "*.cjs" \) -not -path "./node_modules/*" | wc -l) CSS_COUNT=$(find . -type f -name "*.css" -not -path "./node_modules/*" | wc -l) echo "PHP files: $PHP_COUNT" echo "JS files: $JS_COUNT" echo "CSS files: $CSS_COUNT" - name: PHP syntax run: | if find . -type f -name "*.php" -not -path "./vendor/*" | grep -q .; then echo "PHP detected" find . -type f -name "*.php" -not -path "./vendor/*" -print0 | xargs -0 -n1 php -l else echo "No PHP files - skipping" fi - name: Composer run: | if [ -f composer.json ]; then composer validate --no-check-publish if [ -f composer.lock ]; then composer install --no-interaction --prefer-dist --no-progress fi else echo "No composer.json - skipping" fi - name: PHPStan run: | if [ -x vendor/bin/phpstan ]; then vendor/bin/phpstan analyse else echo "PHPStan not installed - skipping" fi - name: PHPUnit run: | if [ -x vendor/bin/phpunit ]; then vendor/bin/phpunit else echo "PHPUnit not installed - skipping" fi - name: Node dependencies run: | if [ -f package-lock.json ]; then npm ci elif [ -f package.json ]; then echo "package.json found but no package-lock.json" else echo "No Node project - skipping" fi - name: JavaScript syntax run: | if find . -type f \( -name "*.js" -o -name "*.mjs" -o -name "*.cjs" \) -not -path "./node_modules/*" | grep -q .; then echo "JavaScript detected" find . -type f \( -name "*.js" -o -name "*.mjs" -o -name "*.cjs" \) \ -not -path "./node_modules/*" \ -print0 | while IFS= read -r -d '' file; do echo "Checking $file" node --check "$file" done else echo "No JavaScript files - skipping" fi - name: ESLint run: | if [ -f package.json ] && \ node -e "let p=require('./package.json'); process.exit(p.scripts?.lint ? 0 : 1)" then npm run lint else echo "No lint script - skipping" fi - name: JavaScript tests run: | if [ -f package.json ] && \ node -e "let p=require('./package.json'); process.exit(p.scripts?.test ? 0 : 1)" then npm test else echo "No JS test script - skipping" fi - name: Frontend build run: | if [ -f package.json ] && \ node -e "let p=require('./package.json'); process.exit(p.scripts?.build ? 0 : 1)" then npm run build else echo "No build script - skipping" fi - name: CSS lint run: | if [ -f package.json ] && \ node -e "let p=require('./package.json'); process.exit(p.scripts?.['lint:css'] ? 0 : 1)" then npm run lint:css else echo "No CSS lint script - skipping" fi - name: Complete run: echo "Davidson CI completed successfully" # ------------------------- # Security # ------------------------- - name: Composer security audit run: | if [ -f composer.lock ]; then echo "Running Composer security audit..." composer audit else echo "No composer.lock - skipping Composer audit" fi - name: npm security audit run: | if [ -f package-lock.json ]; then echo "Running npm security audit..." npm audit --audit-level=high else echo "No package-lock.json - skipping npm audit" fi - name: Semgrep security scan run: | echo "Running Semgrep..." semgrep scan \ --config=p/security-audit \ --error \ --exclude=node_modules \ --exclude=vendor \ . - name: Trivy vulnerability scan run: | echo "Running Trivy vulnerability scan..." trivy fs \ --scanners vuln \ --severity HIGH,CRITICAL \ --exit-code 1 \ . - name: Trivy secret scan run: | echo "Running Trivy secret scan..." trivy fs \ --scanners secret \ --exit-code 1 \ .