wie lokale und Pipeline-Checks zusammenpassen
Wenn PHPStan lokal grün ist aber in der CI-Pipeline rot, liegt es an einer unterschiedlichen Konfiguration. Das Problem ist lösbar: Pre-Commit-Hooks, PhpStorm Quality Gates und CI-Pipeline so aufeinander abstimmen, dass lokal identisch prüft was die Pipeline prüft – kein Push der auf Anhieb fehlschlägt.
Inhaltsverzeichnis
- 1. Das CI-Paritäts-Problem: warum lokal ≠ Pipeline
- 2. Pre-Commit-Hooks: Fehler vor dem Push abfangen
- 3. Lokale Quality Gates in PhpStorm bündeln
- 4. GitHub Actions: PHP Quality Checks in der Pipeline
- 5. GitLab CI: identische Checks mit Docker-Images
- 6. PHPUnit lokal und in CI identisch ausführen
- 7. Caching in CI: Composer und PHPStan-Baseline
- 8. CI-Feedback in PhpStorm sehen
- 9. Vergleich: Workflow mit und ohne lokale CI-Parität
- 10. Zusammenfassung
- 11. FAQ
1. Das CI-Paritäts-Problem: warum lokal ≠ Pipeline
Der häufigste Grund für den Bruch zwischen lokalen und Pipeline-Checks ist Umgebungsunterschiede: Das lokale PHP hat eine andere Version als der CI-Container, Composer-Pakete haben lokal einen anderen Lock-File-Stand, PHPStan läuft mit anderen Konfigurationspfaden oder unterschiedlichem Level. In Docker-basierten Setups ist dieses Problem fast vollständig lösbar, weil man lokal dieselbe Container-Umgebung wie in der Pipeline nutzen kann. Ohne Docker ist die Lücke strukturell schwerer zu schließen.
Ein zweites Problem: Was in PhpStorm als Inspektion angezeigt wird und was die CI-Pipeline prüft, ist oft nicht deckungsgleich. PhpStorm-Inspektionen sind inkrementell und IDE-spezifisch. PHPStan und PHPCS in der Pipeline laufen mit projektspezifischen Konfigurationsdateien die in der IDE nicht automatisch geladen werden. Das Ziel ist deshalb nicht, PhpStorm-Inspektionen durch CI zu ersetzen, sondern beide Ebenen aufeinander abzustimmen und Pre-Commit-Hooks als dritte Ebene dazwischenzuschalten.
Das Drei-Ebenen-Modell für PHP-Qualitätssicherung: (1) PhpStorm-Inspektionen beim Tippen – schnell, inkrementell, unvollständig. (2) Pre-Commit-Hooks beim Commit – vollständig für die geänderten Dateien, blockierend. (3) CI-Pipeline beim Push – vollständig für das gesamte Projekt, authoritative Instanz. Jede Ebene hat ihre Aufgabe, keine ersetzt eine andere.
2. Pre-Commit-Hooks: Fehler vor dem Push abfangen
Git-Hooks im .git/hooks/-Verzeichnis sind das klassische Werkzeug für Pre-Commit-Checks, haben aber einen Nachteil: sie werden nicht ins Repository committed und müssen von jedem Entwickler manuell eingerichtet werden. Das Framework pre-commit (Python-basiert) oder eine einfache composer scripts-Lösung sind bessere Alternativen für PHP-Projekte.
Eine schlanke Lösung ohne externes Framework: Ein Composer-Script pre-commit das PHPCS auf geänderte Dateien und PHPStan auf das Projekt ausführt, plus ein prepare-commit-msg-Hook der dieses Script aufruft. Das Script wird ins Repository committed, der Hook-Verweis wird über composer install automatisch eingerichtet. In der composer.json unter scripts.post-install-cmd wird der Hook-Link gesetzt.
// composer.json — Pre-Commit Integration
{
"scripts": {
// Quality-Gate Skript
"check": [
"@phpcs",
"@phpstan",
"@phpunit-fast"
],
"phpcs": "vendor/bin/phpcs --standard=phpcs.xml",
"phpcbf": "vendor/bin/phpcbf --standard=phpcs.xml",
"phpstan": "vendor/bin/phpstan analyse --no-progress --memory-limit=1G",
"phpunit-fast": "vendor/bin/phpunit --testsuite=unit --no-coverage",
// Hook-Setup nach composer install/update
"post-install-cmd": [
"test -d .git && cp scripts/pre-commit.sh .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit || true"
],
"post-update-cmd": [
"@post-install-cmd"
]
},
"scripts-descriptions": {
"check": "Führt alle Quality-Gate Checks aus (PHPCS + PHPStan + PHPUnit)",
"phpcs": "PHP CodeSniffer: Code-Style prüfen",
"phpcbf": "PHP Code Beautifier: Code-Style automatisch korrigieren",
"phpstan": "PHPStan statische Analyse",
"phpunit-fast": "PHPUnit Unit-Tests (ohne Coverage)"
}
}
PhpStorm kann Composer-Scripts direkt aus dem Composer-Tool-Window ausführen. Das Tool-Window öffnet sich über View → Tool Windows → Composer und listet alle definierten Scripts. Ein Klick auf check führt alle Quality-Gate-Checks aus. Für noch schnelleres Feedback kann man das check-Script als Run Configuration einrichten und auf einen Shortcut legen.
3. Lokale Quality Gates in PhpStorm bündeln
Ein lokales Quality Gate ist ein definierter Checkpoint vor dem Commit der sicherstellt, dass Code bestimmte Qualitätsanforderungen erfüllt. In PhpStorm lässt sich ein Quality Gate als Compound Run Configuration abbilden: Eine Konfiguration die PHPCS, PHPStan und PHPUnit nacheinander ausführt und bei Fehlern abbricht. Das Compound stoppt beim ersten fehlgeschlagenen Schritt, sodass man sofort weiß, welches Tool ein Problem gefunden hat.
Für tägliche Arbeit empfiehlt sich eine abgestufte Strategie: Ein schnelles Quality Gate (PHPCS + PHPStan auf aktueller Datei, unter 5 Sekunden) beim Speichern oder auf Shortcut, und ein vollständiges Quality Gate (alles auf dem gesamten Projekt) vor dem Commit. Das schnelle Gate gibt sofortiges Feedback, das vollständige Gate gibt Sicherheit vor dem Push.
4. GitHub Actions: PHP Quality Checks in der Pipeline
GitHub Actions-Workflows für PHP-Projekte können direkt in PhpStorm bearbeitet werden – die IDE erkennt .github/workflows/*.yml-Dateien und bietet Autovervollständigung für Actions-Syntax. Für maximale Parität mit dem lokalen Docker-Setup empfiehlt sich, denselben PHP-Container-Image in der Pipeline zu verwenden wie lokal.
Ein minimaler, aber vollständiger GitHub Actions-Workflow für PHP-Quality-Checks: PHP-Version pinnen, Composer-Cache nutzen, Composer install, PHPCS, PHPStan und PHPUnit sequenziell ausführen. Jeder Schritt hat einen klaren Namen und das Ergebnis erscheint in der GitHub-UI als einzelner Check-Status. Scheitert PHPStan, weiß man sofort welches Tool das Problem erkannt hat.
# .github/workflows/quality.yml
name: PHP Quality Checks
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
quality:
runs-on: ubuntu-latest
container:
# Gleicher Container wie lokal (Mark Shust Image)
image: markoshust/magento-php:8.4-fpm-0
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Cache Composer packages
uses: actions/cache@v4
with:
path: vendor
key: ${ { runner.os } }-composer-${ { hashFiles('composer.lock') } }
restore-keys: |
${ { runner.os } }-composer-
- name: Install dependencies
run: composer install --prefer-dist --no-progress --no-interaction
- name: PHP_CodeSniffer
run: composer phpcs -- --report=checkstyle | cs2pr
- name: PHPStan
run: composer phpstan
- name: PHPUnit
run: composer phpunit-fast
env:
MAGENTO_UNIT_TEST: "1"
Das Tool cs2pr (Code Style to Pull Request) wandelt PHPCS-Ausgaben in GitHub-Annotations um, die direkt im Pull Request als Kommentare erscheinen. So sieht der Entwickler beim Code-Review genau, in welcher Zeile ein PHPCS-Verstoß liegt, ohne die Rohausgabe lesen zu müssen. Installation: composer require --dev staabm/annotate-pull-request-from-checkstyle.
5. GitLab CI: identische Checks mit Docker-Images
GitLab CI funktioniert analog zu GitHub Actions, nutzt aber eine andere YAML-Syntax und bietet native Docker-Registry-Integration. Der Vorteil bei GitLab: Man kann eigene Docker-Images mit vorinstallierten PHP-Abhängigkeiten in der eigenen Registry hosten, was Pipeline-Startzeiten erheblich reduziert.
In .gitlab-ci.yml definiert man einen Pipeline-Job pro Quality-Tool. Mit GitLab-CI-Artifacts kann man PHPUnit-Coverage-Reports und PHPStan-Ausgaben als downloadbare Artefakte der Pipeline anhängen. Das erlaubt Nachuntersuchungen wenn ein Pipeline-Lauf fehlschlägt, ohne den Check lokal neu auszuführen. PhpStorm Ultimate hat eine native GitLab-CI-Integration, die Pipeline-Status direkt in der IDE anzeigt.
6. PHPUnit lokal und in CI identisch ausführen
PHPUnit-Konfiguration muss identisch sein zwischen lokaler Ausführung und CI. Die wichtigste Quelle für Divergenz: Umgebungsvariablen. Magento-Unit-Tests brauchen bestimmte Konstanten und Pfade, die lokal im Container verfügbar sind aber in der CI gesetzt werden müssen. Mit einer phpunit.xml.dist im Repository und einer lokalen phpunit.xml (die in .gitignore steht) kann man beide Szenarien abdecken.
PhpStorm liest die phpunit.xml.dist automatisch für Run Configurations. Die Bootstrap-Datei lädt Magento-spezifische Konstanten und Autoloader. In der CI-Pipeline referenziert der PHPUnit-Aufruf dieselbe Konfigurationsdatei, was identisches Verhalten sicherstellt. Code-Coverage sollte lokal auf Abruf und in der CI auf jedem PR-Build laufen – aber nie in Pre-Commit-Hooks, da sie zu langsam sind.
<?xml version="1.0" encoding="UTF-8"?>
<!-- phpunit.xml.dist — Repository-Konfiguration für CI und lokale Ausführung -->
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="src/dev/tests/unit/framework/bootstrap.php"
colors="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTestsThatDoNotTestAnything="true"
>
<testsuites>
<testsuite name="unit">
<directory>src/app/code/Mironsoft/*/Test/Unit</directory>
</testsuite>
<testsuite name="integration">
<directory>src/app/code/Mironsoft/*/Test/Integration</directory>
</testsuite>
</testsuites>
<source>
<include>
<directory>src/app/code/Mironsoft</directory>
</include>
<exclude>
<directory>src/app/code/Mironsoft/*/Test</directory>
</exclude>
</source>
<php>
<!-- Umgebungsvariablen für Magento-Tests -->
<env name="MAGENTO_ROOT" value="src"/>
<env name="TESTS_CLEANUP" value="enabled"/>
</php>
</phpunit>
7. Caching in CI: Composer und PHPStan-Baseline
Caching ist der wichtigste Hebel für schnelle CI-Pipelines. Ohne Caching läuft composer install bei jedem Commit von Grund auf und dauert bei großen PHP-Projekten mehrere Minuten. Mit einem Composer-Cache basierend auf dem Hash des composer.lock wird install zum Entpacken bereits gecachter Pakete – sekunden statt Minuten.
PHPStan-Baseline-Dateien müssen in der CI als Artefakt zwischen Builds verfügbar sein. Wenn die Baseline lokal generiert und ins Repository committed wird, ist das kein Problem – sie wird zusammen mit dem Code ausgecheckt. Wichtig: die Baseline nicht in .gitignore eintragen. PHPStan-interne Caches (/tmp/phpstan/) können ebenfalls in der CI gecacht werden, bringen aber weniger Gewinn als der Composer-Cache.
8. CI-Feedback in PhpStorm sehen
PhpStorm Ultimate hat eine GitHub-Integration, die Pull-Request-Status, Check-Ergebnisse und Code-Review-Kommentare direkt in der IDE anzeigt. Das Plugin GitHub (nativ in PhpStorm Ultimate) zeigt im Pull Requests-Tool-Window alle offenen PRs mit ihrem CI-Status. Scheitert ein CI-Job, erscheint das sofort in PhpStorm – ohne den Browser öffnen zu müssen.
Für GitLab-Projekte gibt es ein analoges Plugin. In beiden Fällen lohnt es sich, die CI-Benachrichtigung so zu konfigurieren, dass nur Failures und nicht jeder erfolgreiche Build eine IDE-Notification auslöst. Zu viele Benachrichtigungen führen zu Gewöhnung und werden ignoriert. Besser: Notifications nur bei roten Builds, und grüne Builds als passives Status-Icon im IDE-Footer.
9. Vergleich: Workflow mit und ohne lokale CI-Parität
Der Unterschied im täglichen Workflow zwischen einem Setup ohne und mit lokaler CI-Parität ist erheblich – nicht nur in der Anzahl fehlgeschlagener Pipeline-Läufe, sondern auch in der Zeit die Entwickler mit Debugging und Kontext-Wechseln verbringen.
| Aspekt | Ohne Parität | Mit lokaler Parität | Zeitersparnis |
|---|---|---|---|
| Fehlererkennung | Nach Push in CI (Minuten) | Beim Commit (Sekunden) | 5–15 Min. pro Fehler |
| Kontext-Wechsel | IDE → GitHub → IDE | Innerhalb der IDE | Kognitive Last deutlich reduziert |
| Pipeline-Kosten | Viele unnötige Läufe | Nur valider Code pushed | CI-Minuten reduziert |
| Code-Review-Qualität | Style-Fixes in Reviews | Reviews nur für Logik | Reviews fokussierter und kürzer |
| Onboarding | Jeder Entwickler eigene Praxis | Einheitliche Quality Gates | Neue Entwickler schneller produktiv |
Die Investition in lokale CI-Parität ist primär eine Konfigurationsaufgabe: Docker-Setup, identische PHP-Versionen, geteilte Konfigurationsdateien (phpstan.neon, phpcs.xml, phpunit.xml.dist) und Pre-Commit-Hooks. Einmal eingerichtet, läuft das System ohne weiteren Aufwand und hält das Qualitätsniveau automatisch hoch.
10. Zusammenfassung
Das Kernproblem zwischen lokalen und Pipeline-Checks ist Umgebungsinkonsistenz: unterschiedliche PHP-Versionen, unterschiedliche Konfigurationsdateien, fehlende Umgebungsvariablen. Die Lösung ist konsequente Parität: Docker-Setup lokal und in CI, geteilte Konfigurationsdateien im Repository, Pre-Commit-Hooks die dieselben Tools mit denselben Konfigurationen ausführen wie die Pipeline.
PhpStorm spielt in diesem Setup die Rolle des Frühwarnsystems: schnelle inkrementelle Feedback-Schleife beim Tippen. Pre-Commit-Hooks sind das Sicherheitsnetz vor dem Commit. Die CI-Pipeline ist die authoritative Prüfinstanz und sieht nur Code der bereits lokal geprüft wurde. Composer-Scripts als gemeinsame Abstraktionsebene stellen sicher, dass alle drei Ebenen dieselben Befehle nutzen.
PhpStorm & CI/CD — Das Wichtigste auf einen Blick
Drei-Ebenen-Modell
PhpStorm (beim Tippen) → Pre-Commit-Hook (beim Commit) → CI-Pipeline (beim Push). Jede Ebene hat ihre Aufgabe, keine ersetzt eine andere.
Composer-Scripts
Gemeinsame Abstraktionsebene: composer check ruft PHPCS, PHPStan, PHPUnit auf. Lokal, im Pre-Commit-Hook und in CI identisch.
GitHub Actions
PHP-Version pinnen, Composer-Cache, PHPCS mit cs2pr für PR-Annotations, PHPStan, PHPUnit sequenziell. Gleicher Docker-Container wie lokal.
CI-Feedback in IDE
PhpStorm Ultimate: GitHub/GitLab-Plugin zeigt PR-Status direkt in IDE. Notifications nur bei Failures. Grüne Builds als passiver Status-Indikator.
Mironsoft
CI/CD-Integration, Quality Gates und DevOps für PHP-Teams
Quality Gates die lokal und in CI identisch laufen?
Wir richten Pre-Commit-Hooks, PhpStorm Quality Gates und CI-Pipelines so ein, dass lokal identisch prüft was die Pipeline prüft – kein Push der auf Anhieb fehlschlägt, kein Warten auf CI-Feedback für korrigierbaren Code.
Pre-Commit Setup
Composer-Scripts, Git-Hooks und PhpStorm Run Configurations für lokale Quality Gates einrichten
CI-Pipeline
GitHub Actions oder GitLab CI mit Caching, PR-Annotations und identischem Container wie lokal
PHPUnit CI
PHPUnit-Konfiguration für lokale und CI-Ausführung harmonisieren – Coverage-Reports als CI-Artefakte
11. FAQ: PhpStorm und CI/CD
1PHPStan lokal grün, CI rot – warum?
2Pre-Commit-Hooks für PHP einrichten?
check definieren. Bash-Hook nach .git/hooks/pre-commit kopieren. Via post-install-cmd automatisch einrichten.3Was ist cs2pr?
4Coverage lokal oder in CI?
5CI-Status in PhpStorm anzeigen?
6Vorteil von Composer-Scripts?
composer phpstan läuft lokal, im Hook und in CI identisch. Keine doppelte Konfiguration, keine Divergenz.7Composer cachen in GitHub Actions?
actions/cache@v4 mit path: vendor und key: ...-${ { hashFiles('composer.lock') } }. Cache-Hit: Sekunden statt Minuten für install.8Pre-Commit-Hooks nicht zu langsam machen?
9Welche Konfigurationsdateien ins Repo?
10Run Configurations mit CI synchronisieren?
composer check auf, CI-Job ebenfalls. Beide sind automatisch synchron – gleicher Einstiegspunkt.