Redesign, Bugfixes, more improvements #674
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: PHP CI | |
| on: | |
| push: | |
| branches: ["main"] | |
| pull_request: | |
| branches: ["main"] | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| jobs: | |
| # ───────────────────────────────────────────── | |
| # 1. Build & Validate (PHP 8.1 – 8.4) | |
| # ───────────────────────────────────────────── | |
| build: | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| php-version: ['8.1', '8.2', '8.3', '8.4'] | |
| fail-fast: false | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Setup PHP ${{ matrix.php-version }} | |
| uses: shivammathur/setup-php@v2 | |
| with: | |
| php-version: ${{ matrix.php-version }} | |
| extensions: mbstring, pdo, pdo_mysql, json, curl, gd, intl | |
| coverage: none | |
| - name: Validate composer.json and composer.lock | |
| run: composer validate --strict | |
| - name: Cache Composer packages | |
| uses: actions/cache@v4 | |
| with: | |
| path: vendor | |
| key: ${{ runner.os }}-php-${{ matrix.php-version }}-${{ hashFiles('**/composer.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-php-${{ matrix.php-version }}- | |
| - name: Update lock file | |
| run: composer update --lock | |
| - name: Install dependencies | |
| run: composer install --prefer-dist --no-progress | |
| - name: PHP Lint | |
| run: find . -name "*.php" -not -path "./vendor/*" -print0 | xargs -0 -n1 php -l | |
| # ───────────────────────────────────────────── | |
| # 2. Build PHP 8.5 (experimentell, blockiert nicht) | |
| # ───────────────────────────────────────────── | |
| build-experimental: | |
| name: "experimental build (8.5)" | |
| if: false # Pausiert – Zeile entfernen zum Reaktivieren | |
| runs-on: ubuntu-latest | |
| continue-on-error: true | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Setup PHP 8.5 | |
| uses: shivammathur/setup-php@v2 | |
| with: | |
| php-version: '8.5' | |
| extensions: mbstring, pdo, pdo_mysql, json, curl, gd, intl | |
| coverage: none | |
| - name: Validate composer.json and composer.lock | |
| run: composer validate --strict | |
| - name: Cache Composer packages | |
| uses: actions/cache@v4 | |
| with: | |
| path: vendor | |
| key: ${{ runner.os }}-php-8.5-${{ hashFiles('**/composer.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-php-8.5- | |
| - name: Update lock file | |
| run: composer update --lock | |
| - name: Install dependencies | |
| run: composer install --prefer-dist --no-progress | |
| - name: PHP Lint | |
| run: find . -name "*.php" -not -path "./vendor/*" -print0 | xargs -0 -n1 php -l | |
| # ───────────────────────────────────────────── | |
| # 3. Security Audit | |
| # ───────────────────────────────────────────── | |
| security-audit: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Setup PHP | |
| uses: shivammathur/setup-php@v2 | |
| with: | |
| php-version: '8.4' | |
| - name: Install dependencies | |
| run: composer install --prefer-dist --no-progress | |
| - name: Check for known vulnerabilities | |
| run: composer audit | |
| # ───────────────────────────────────────────── | |
| # 4. PHPStan – Statische Analyse | |
| # ───────────────────────────────────────────── | |
| phpstan: | |
| runs-on: ubuntu-latest | |
| needs: build | |
| if: ${{ !cancelled() }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Setup PHP | |
| uses: shivammathur/setup-php@v2 | |
| with: | |
| php-version: '8.4' | |
| extensions: mbstring, pdo, pdo_mysql, json, curl, gd, intl | |
| - name: Cache Composer packages | |
| uses: actions/cache@v4 | |
| with: | |
| path: vendor | |
| key: ${{ runner.os }}-php-8.4-${{ hashFiles('**/composer.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-php-8.4- | |
| - name: Install dependencies | |
| run: composer install --prefer-dist --no-progress | |
| # Inline-Annotations in geänderten Dateien im PR-Diff | |
| - name: PHPStan – Inline Annotations | |
| run: vendor/bin/phpstan analyse --no-progress --error-format=github || true | |
| # JSON-Output für den PR-Kommentar | |
| - name: PHPStan – Report generieren | |
| id: phpstan | |
| run: | | |
| set +e | |
| vendor/bin/phpstan analyse --no-progress --error-format=json > phpstan-result.json 2>/dev/null | |
| echo "exit_code=$?" >> "$GITHUB_OUTPUT" | |
| - name: PHPStan-Ergebnis im PR posten | |
| if: always() && github.event_name == 'pull_request' | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| const exitCode = '${{ steps.phpstan.outputs.exit_code }}'; | |
| let json; | |
| try { | |
| json = JSON.parse(fs.readFileSync('phpstan-result.json', 'utf8')); | |
| } catch { | |
| json = null; | |
| } | |
| // ── Kommentar bauen ── | |
| let body = '<!-- phpstan-report -->\n'; | |
| if (exitCode === '0') { | |
| body += '## ✅ Keine Fehler\n\n'; | |
| body += 'Keine Probleme gefunden. 🎉\n'; | |
| } else if (json?.files && Object.keys(json.files).length > 0) { | |
| const files = json.files; | |
| const totalErrors = json.totals?.file_errors || 0; | |
| const fileCount = Object.keys(files).length; | |
| body += `## ⚠️ ${totalErrors} Fehler in ${fileCount} Dateien\n\n`; | |
| // Runner-Workspace-Pfad entfernen, Projektpfade beibehalten | |
| const workspacePrefix = process.env.GITHUB_WORKSPACE ? process.env.GITHUB_WORKSPACE + '/' : ''; | |
| const shortPath = (p) => workspacePrefix ? p.replace(workspacePrefix, '') : p; | |
| // ── Zusammenfassung (immer sichtbar) ── | |
| body += '| Datei | Fehler |\n'; | |
| body += '|-------|-------:|\n'; | |
| for (const [filePath, data] of Object.entries(files)) { | |
| body += `| \`${shortPath(filePath)}\` | ${data.messages.length} |\n`; | |
| } | |
| // ── Details pro Datei (aufklappbar) ── | |
| body += '\n---\n\n'; | |
| for (const [filePath, data] of Object.entries(files)) { | |
| const short = shortPath(filePath); | |
| body += `<details>\n<summary><strong>${short}</strong> (${data.messages.length} Fehler)</summary>\n\n`; | |
| body += '| Zeile | Beschreibung |\n'; | |
| body += '|------:|--------------|\n'; | |
| for (const msg of data.messages) { | |
| const desc = msg.message.replace(/\|/g, '\\|'); | |
| body += `| ${msg.line} | ${desc} |\n`; | |
| } | |
| body += '\n</details>\n\n'; | |
| } | |
| } else { | |
| body += '## ❌ Unbekannter Fehler\n\n'; | |
| body += 'Ergebnis konnte nicht verarbeitet werden. Siehe [Workflow-Log](' + | |
| `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}).\n`; | |
| } | |
| // ── Alten Kommentar ersetzen ── | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| }); | |
| const old = comments.find(c => c.body?.includes('<!-- phpstan-report -->')); | |
| if (old) { | |
| await github.rest.issues.deleteComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: old.id, | |
| }); | |
| } | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body, | |
| }); | |
| - name: PHPStan Exit Code | |
| if: always() | |
| run: exit ${{ steps.phpstan.outputs.exit_code }} |