PhpStorm und CI/CD: wie lokale Checks und Pipeline-Checks zusammenpassen
AI generated
IDE
{ }
PhpStorm · CI/CD · GitHub Actions · Pre-Commit · Quality Gates
PhpStorm und CI/CD:
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.

20 Min. Lesezeit Pre-Commit · GitHub Actions · GitLab CI · PHPStan · PHPCS · PHPUnit PhpStorm 2024+ · PHP 8.4 · Docker

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?
Unterschiedliche PHP-Version, Composer-Lock-Stand oder phpstan.neon. Lösung: Docker lokal mit identischem CI-Image. Alle Konfigurationsdateien ins Repo.
2Pre-Commit-Hooks für PHP einrichten?
Composer-Script check definieren. Bash-Hook nach .git/hooks/pre-commit kopieren. Via post-install-cmd automatisch einrichten.
3Was ist cs2pr?
Wandelt PHPCS-Ausgaben in GitHub-PR-Annotations um. Verstöße erscheinen direkt als Kommentare im Pull Request, nicht nur als Pipeline-Logs.
4Coverage lokal oder in CI?
Coverage: nicht in Pre-Commit (zu langsam). Lokal auf Abruf in PhpStorm. In CI auf jedem PR-Build als Artefakt. Beides sinnvoll, aber getrennt.
5CI-Status in PhpStorm anzeigen?
PhpStorm Ultimate: GitHub/GitLab-Plugin. View → Tool Windows → Pull Requests. Nur Failures als Notification, grüne Builds als Footer-Status.
6Vorteil von Composer-Scripts?
Portable Abstraktionsebene: 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?
Nur schnelle Checks im Pre-Commit: PHPCS + PHPStan auf geänderte Dateien. Langsame Checks (volle PHPUnit, Coverage) in CI. Ziel: unter 30 Sekunden.
9Welche Konfigurationsdateien ins Repo?
phpstan.neon, phpstan-baseline.neon, phpcs.xml, phpunit.xml.dist, .github/workflows/*.yml, composer.lock, scripts/pre-commit.sh.
10Run Configurations mit CI synchronisieren?
Indirekt über Composer-Scripts: Run Config ruft composer check auf, CI-Job ebenfalls. Beide sind automatisch synchron – gleicher Einstiegspunkt.