Semantic Versioning (SemVer) in einem Symfony-Projekt

Um Semantic Versioning (SemVer) in einem Symfony-Projekt mit Git zu automatisieren, kannst du eine Kombination aus Git-Hooks und einem Skript verwenden, das die Versionsnummern in einer Datei verwaltet und automatisch aktualisiert. Hier ist eine Schritt-für-Schritt-Anleitung, wie du dies einrichten kannst:

1. Skript zum Inkrementieren der Versionsnummer

Erstelle ein PHP-Skript, das die Versionsnummer basierend auf dem Typ der Änderung (PATCH, MINOR, MAJOR) automatisch erhöht. Nenne das Skript z.B. update_version.php.

<?php

function incrementVersion(string $version, string $type = 'patch'): string
{
    $parts = explode('.', $version);

    switch ($type) {
        case 'major':
            $parts[0]++;
            $parts[1] = 0;
            $parts[2] = 0;
            break;
        case 'minor':
            $parts[1]++;
            $parts[2] = 0;
            break;
        case 'patch':
        default:
            $parts[2]++;
            break;
    }

    return implode('.', $parts);
}

$versionFilePath = __DIR__ . '/version.txt';
$defaultVersion = '0.1.0';

// Check if the file exists
if (!file_exists($versionFilePath)) {
    // Create the file and write the default version
    file_put_contents($versionFilePath, $defaultVersion);
    print "version.txt created with version $defaultVersion\n";
} else {
    $currentVersion = trim(file_get_contents($versionFilePath));

    // Get the argument to determine the type of increment (patch, minor, major)
    $type = $argv[1] ?? 'patch';

    $newVersion = incrementVersion($currentVersion, $type);

    file_put_contents($versionFilePath, $newVersion);

    print "Version updated to $newVersion\n";
}

2. Git Hook einrichten

Ein Git Hook ist ein Skript, das bei bestimmten Git-Ereignissen ausgeführt wird. Für die automatische Versionsaktualisierung nutzen wir den pre-commit-Hook.

  • Erstelle eine Datei .git/hooks/pre-commit (falls sie nicht existiert) und mache sie ausführbar:
touch .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
  • Füge folgendes in die Datei .git/hooks/pre-commit ein:
#!/bin/sh

# Typ der Änderung über Argumente bestimmen oder default auf "patch"
VERSION_TYPE=${1:-patch}

# Versionsnummer erhöhen
php update_version.php $VERSION_TYPE

# version.txt zum Commit hinzufügen
git add version.txt

Dieser Hook führt das update_version.php-Skript aus und erhöht die Versionsnummer basierend auf dem übergebenen Argument (patch, minor, major). Danach wird die aktualisierte version.txt automatisch zum Commit hinzugefügt.

3. Verwendung

Bei jedem Commit wird die Versionsnummer automatisch aktualisiert. Standardmäßig wird die PATCH-Version erhöht. Du kannst den Typ der Versionserhöhung beim Commit angeben:

  • Für einen Patch (Standard):
git commit -m "Bugfix: ... "
  • Für ein Minor-Update:
git commit -m "New feature: ..." && git commit --amend -m "New feature: ..." && git hook run pre-commit minor
  • Für ein Major-Update:
git commit -m "Breaking change: ..." && git commit --amend -m "Breaking change: ..." && git hook run pre-commit major

4. Optional: Automatisierung der Commit-Nachricht

Um den Typ der Änderung besser im Workflow zu integrieren, kannst du ein weiteres Skript oder eine Konvention einführen, um den Typ der Änderung aus der Commit-Nachricht abzuleiten, und entsprechend die Versionsnummer zu erhöhen.

5. CI/CD Integration

Wenn du ein CI/CD-Tool verwendest (z.B. GitLab CI, GitHub Actions), kannst du diese Versionierungsschritte auch dort automatisieren, indem du das update_version.php-Skript in deine Pipeline integrierst.

Mit diesen Schritten hast du eine einfache, automatisierte Lösung, die SemVer in deinem Symfony-Projekt mithilfe von Git-Hooks implementiert. Die Versionsnummer wird bei jedem Commit basierend auf den vorgenommenen Änderungen aktualisiert und in der version.txt gespeichert.

ESLint zum Testen von JavaScript in Symfony-Projekten mit npm unter XAMPP installieren

Diese Anleitung beschreibt, wie ESLint in einem Symfony-Projekt verwendet werden kann, um JavaScript-Code zu testen. Die Schritte umfassen die Installation von npm unter Windows mit XAMPP und die Integration von ESLint in ein Symfony-Projekt.

Schritt 1: Node.js und npm unter Windows installieren

  1. Node.js-Installer herunterladen:
  • Besuche die Node.js-Website.
  • Wähle die LTS-Version (Long Term Support) für eine stabilere Umgebung.
  • Lade den Installer für Windows herunter.
  1. Node.js installieren:
  • Führe die heruntergeladene .msi-Datei aus.
  • Folge den Anweisungen des Installationsassistenten. Node.js und npm werden automatisch installiert. Die Default-Einstellungen sind ausreichend.
  1. Installation überprüfen:
  • Öffne die Eingabeaufforderung (Cmd) oder PowerShell.
  • Überprüfe die Node.js-Version mit node -v.
  • Überprüfe die npm-Version mit npm -v.

Schritt 2: Integration von npm in ein XAMPP-Projekt

  1. Projektverzeichnis auswählen:
  • Öffne die Eingabeaufforderung oder PowerShell.
  • Navigiere zum Projektverzeichnis unter C:\xampp\htdocs\dein-projekt.
  1. npm-Projekt initialisieren:
  • Führe npm init aus, um ein neues npm-Projekt zu initialisieren. Eine package.json-Datei wird erstellt.
  • Die Standardeinstellungen können durch Drücken der Eingabetaste akzeptiert werden.
  1. ESLint als Entwicklungsabhängigkeit installieren:
  • Installiere ESLint mit dem folgenden Befehl: npm install eslint --save-dev
  • ESLint wird im node_modules-Ordner des Projekts installiert.

Schritt 3: ESLint konfigurieren und verwenden

  1. ESLint konfigurieren:
  • Führe den Befehl npx eslint --init aus, um ESLint in deinem Projekt zu konfigurieren.
  • Beantworte die Fragen, um die Konfiguration den Projektanforderungen anzupassen. Eine .eslintrc.json-Datei wird erstellt.

Inhalt der eslint.config.mjs

import globals from "globals";
import pluginJs from "@eslint/js";


export default [
  {files: ["**/*.js"], languageOptions: {sourceType: "script"}},
  {languageOptions: { globals: globals.browser }},
  pluginJs.configs.recommended,
];

Zusammenarbeit mit jQuery

Um überflüssige, genauer gesagt „falsche“ Fehler zu beheben, muss in der ESLint-Konfiguration angegeben werden, dass jQuery verwendet wird. Ansonsten gibt es gleich Hunderte von „error ‘$’ is not defined“ Meldungen, weil ESLint nicht weiß, dass $ aus der jQuery-Bibliothek stammt.

import globals from "globals";
import pluginJs from "@eslint/js";

export default [
  {
    files: ["**/*.js"],
    languageOptions: {
      sourceType: "script",
      globals: {
        ...globals.browser,
        $: "readonly",
        jQuery: "readonly",
      },
    },
  },
  pluginJs.configs.recommended,
];

  1. JavaScript-Code mit ESLint überprüfen:
  • Verwende den folgenden Befehl, um JavaScript-Dateien im Projekt zu überprüfen: npx eslint path/to/yourfile.js
  • ESLint überprüft die Datei auf mögliche Fehler und gibt entsprechende Meldungen aus.
  • Ich selbst nutze am liebsten folgenden Befehl, um alle Javascript-Dateien auf einmal zu prüfen:
npx eslint .\public\js\
  1. Automatische Korrektur von Fehlern:
  • Fehler können automatisch korrigiert werden, indem --fix an den Befehl angehängt wird: npx eslint path/to/yourfile.js --fix

Schritt 4: ESLint in den Entwicklungsworkflow integrieren

  1. npm-Skripte für ESLint erstellen:
  • In der package.json können npm-Skripte definiert werden, um ESLint leicht im Entwicklungsprozess zu verwenden. Zum Beispiel: "scripts": { "lint": "eslint . --ext .js,.jsx", "lint:fix": "eslint . --ext .js,.jsx --fix" }
  • Diese Skripte können dann mit npm run lint oder npm run lint:fix ausgeführt werden.

Mit diesen Schritten ist ESLint in ein Symfony-Projekt integriert und kann verwendet werden, um JavaScript-Code zu überprüfen und zu verbessern. Die Verwendung von ESLint sorgt für sauberen, fehlerfreien Code, der den Best Practices entspricht.

Verwendung von PHPStan mit Symfony und GIT Pre-Commit Hook

Diese Anleitung beschreibt die Integration von PHPStan in ein Symfony-Projekt und die Einrichtung eines GIT Pre-Commit Hooks, um sicherzustellen, dass der PHPStan-Check vor jedem Push-Vorgang durchgeführt wird.

Voraussetzungen

  • Ein Symfony-Projekt
  • PHPStan installiert (idealerweise als Composer-Abhängigkeit)
  • GIT installiert und eingerichtet

1. Installation von PHPStan

Falls PHPStan noch nicht im Projekt installiert ist, erfolgt die Installation über Composer:

composer require --dev phpstan/phpstan

2. PHPStan Konfiguration

In der Regel wird PHPStan mit einer Konfigurationsdatei verwendet, um spezifische Regeln und Pfade für die Analyse festzulegen.

  1. Eine Datei phpstan.neon oder phpstan.neon.dist im Projektstammverzeichnis anlegen.
  2. Grundlegende Konfiguration einfügen:
parameters:
    level: 6
    paths:
        - config/
        - public/
        - src/
        - tests/
  • level: Der PHPStan-Level bestimmt die Strenge der Analysen. Stufen reichen von 0 (am wenigsten streng) bis 9 (am strengsten).
  • paths: Verzeichnisse, die analysiert werden sollen.

3. Lokales Ausführen von PHPStan

Um sicherzustellen, dass PHPStan korrekt funktioniert, sollte es manuell ausgeführt werden:

vendor/bin/phpstan analyse

Falls Fehler oder Warnungen ausgegeben werden, sollten diese vor dem nächsten Schritt behoben werden.

4. Einrichten des GIT Pre-Commit Hooks

Um sicherzustellen, dass PHPStan vor jedem Commit ausgeführt wird, wird ein Pre-Commit Hook eingerichtet. Dieser Hook wird jedes Mal ausgeführt, wenn ein git commit ausgeführt wird.

  1. Ein neues Verzeichnis .git/hooks im Projektstammverzeichnis öffnen.
  2. Eine Datei namens pre-commit erstellen (ohne Dateierweiterung).
  3. Folgendes Skript in die Datei pre-commit einfügen (oder ergänzen):
#!/bin/sh

# Listet alle Dateien auf, die für den Commit vorgemerkt sind
staged_files=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.php$')

# Wenn keine PHP-Dateien im Commit sind, überspringe die Überprüfung
if [ -z "$staged_files" ]; then
    echo "Keine PHP-Dateien zum Überprüfen."
    exit 0
fi

# Ausführen von PHPStan nur auf den vorgemerkten Dateien
vendor/bin/phpstan analyse $staged_files
if [ $? -ne 0 ]; then
    echo "PHPStan hat Fehler in den vorgemerkten Dateien gefunden. Commit wird abgebrochen."
    exit 1
fi
  1. Die Datei ausführbar machen:
chmod +x .git/hooks/pre-commit

5. Testen des Pre-Commit Hooks

Nach der Einrichtung kann der Pre-Commit Hook getestet werden, indem ein Commit ausgeführt wird:

git commit -m"Test Pre-Commit Hook"

Falls PHPStan Fehler findet, wird der Commit abgebrochen, und die entsprechenden Fehlermeldungen werden ausgegeben. Nur wenn PHPStan fehlerfrei durchläuft, wird der Commit-Vorgang fortgesetzt.

Anleitung zur Verwendung von PHP_CodeSniffer mit Symfony und GIT pre-commit Hook

Ziel: Sicherstellen, dass dein PHP-Code den definierten Codierungsstandards entspricht, bevor er ins Repository gepusht wird. Dies erfolgt durch Integration von PHP_CodeSniffer mit PHPUnit in einem pre-commit Hook.


1. Installation von PHP_CodeSniffer

  1. Installiere PHP_CodeSniffer via Composer:
composer require --dev squizlabs/php_codesniffer
  1. Überprüfe die verfügbaren Standards
./vendor/bin/phpcs -i

Dieser Befehl zeigt eine Liste aller verfügbaren Coding-Standards an. Bspw:

The installed coding standards are MySource, PEAR, PSR1, PSR2, PSR12, Squiz and Zend

2. Konfiguration von PHP_CodeSniffer

  1. Erstelle/konfiguriere eine phpcs.xml.dist im Root-Verzeichnis:
<?xml version="1.0"?>
<ruleset name="CustomRules">
    <file>src</file>
    <file>tests</file>
    
    <!-- Verwenden Sie die PSR-12-Regel als Basis -->
    <rule ref="PSR12"/>

    <!-- Prüfen auf TODO-Kommentare -->
    <rule ref="Generic.Commenting.Todo"/>
</ruleset>
  1. Konfiguriere das phpcs-Tool in deiner phpunit.xml.dist:
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
    bootstrap="vendor/autoload.php"
    colors="true"
    verbose="true"
    stopOnFailure="false"
    failOnWarning="true"
    failOnRisky="true"
    stopOnError="false"
    stopOnWarning="false"
>
    <testsuites>
        <testsuite name="Application Test Suite">
            <directory>./tests</directory>
        </testsuite>
    </testsuites>

    <!-- Optional: PHPUnit Listener für PHP_CodeSniffer Integration -->
    <listeners>
        <listener class="PHP_CodeSniffer\Standards\PHPUnit\PHPUnitListener">
            <arguments>
                <string>--standard=PSR12</string>
            </arguments>
        </listener>
    </listeners>
</phpunit>


3. Integration in den GIT pre-commit Hook

  1. Erstelle (oder ergänze) den pre-commit Hook in .git/hooks/pre-commit
#!/bin/sh

# Listet alle Dateien auf, die für den Commit vorgemerkt sind
staged_files=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.php$')

# Wenn keine PHP-Dateien im Commit sind, überspringe die Überprüfung
if [ -z "$staged_files" ]; then
    echo "Keine PHP-Dateien zum Überprüfen."
    exit 0
fi

# Ausführen von PHP_CodeSniffer nur auf den vorgemerkten Dateien
./vendor/bin/phpcs -n $staged_files
if [ $? -ne 0 ]; then
    echo "PHP_CodeSniffer hat Fehler in den vorgemerkten Dateien gefunden. Commit wird abgebrochen."
    exit 1
fi
  1. Mach den pre-commit Hook ausführbar:
chmod +x .git/hooks/pre-commit

4. Wichtige Ausgaben verstehen

  • phpcs: Zeigt Verstöße gegen die Coding-Standards an.
  • phpcbf: Automatische Korrektur von einfachen Verstößen.
./vendor/bin/phpcs -n # Der Schalter -n unterdrückt harmlose Warnings
./vendor/bin/phpcbf --standard=phpcs.xml.dist src/

Natürlich können phpcs und phpcbf mit einzelnen Dateien aufgerufen werden.

  • Fehler und Warnungen: Werden als „ERROR“ oder „WARNING“ gekennzeichnet.
  • Details zur Korrektur: Werden spezifisch zu den betroffenen Dateien und Zeilen angezeigt.

5. Fazit

Mit dieser Integration stellst du sicher, dass dein Code den Coding-Standards entspricht und Tests erfolgreich durchlaufen, bevor du deine Änderungen ins Repository pusht. Dies verbessert die Codequalität und reduziert potenzielle Fehler im Produktionscode erheblich.

PHPUnit und Git Push zum automatisierten Vergleich von Datenbankschemata zwischen Entwicklungs- und Produktionsumgebung

Einführung

Wenn Sie in einer Entwicklungsumgebung arbeiten und Ihre Änderungen auf eine Produktionsumgebung übertragen, kann es leicht passieren, dass sich kleine, aber kritische Unterschiede in den Datenbankschemata einschleichen. Diese Unterschiede können zu Fehlern führen, die erst im laufenden Betrieb auffallen. Um solche Probleme zu vermeiden, ist es entscheidend, die Datenbankschemata zwischen der Entwicklungs- und der Produktionsumgebung vor einem Deployment zu vergleichen.

In diesem Artikel zeige ich Ihnen, wie Sie mit einer automatisierten PHPUnit-Testklasse sicherstellen können, dass die Datenbankschemata auf beiden Umgebungen identisch sind. Dieser Test wird in Ihrem CI/CD-Prozess integriert und verhindert so den Push, wenn ein Fehler gefunden wird.

Warum ist der Vergleich von Datenbankschemata wichtig?

Ich selbst vergesse regelmäßig, die Datenbank auf der Produktionsumgebung nachzuziehen – was besonders schlimm ist, wenn es im laufenden Betrieb nicht gleich auffällt.

Erstellen eines PHPUnit-Tests zum Vergleich der Datenbankschemata

Wenn Sie PHPUnit noch nicht installiert haben, können Sie es über Composer installieren. Führen Sie den folgenden Befehl im Stammverzeichnis des Projekts aus:

composer require --dev phpunit/phpunit

Um die Datenbankschemata zu vergleichen, erstellen wir einen PHPUnit-Test, der die Tabellen und Spalten in den lokalen und den Remote-Datenbanken überprüft. Dieser Test sammelt alle Fehler und gibt sie gesammelt am Ende des Tests aus. Wir erstellen die Datei tests/DatabaseSchemaTest.php. Der Code sollte selbsterklärend sein.

In PHP-Projekten ist es üblich, Tests im Verzeichnis tests zu organisieren. Der Name der Datei sollte auf .php enden und den Namen der Testklasse widerspiegeln.

<?php

// tests/DatabaseSchemaTest.php
// CLI: vendor/bin/phpunit --filter DatabaseSchemaTest

namespace App\Tests;

use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DriverManager;
use PHPUnit\Framework\TestCase;

class DatabaseSchemaTest extends TestCase
{
    private $localDb1Connection;
    private $remoteDb1Connection;
    private $localDb2Connection;
    private $remoteDb2Connection;

    protected function setUp(): void
    {
        $this->localDb1Connection = DriverManager::getConnection(['url' => 'mysql://user:pass@localhost/local_db1']);
        $this->remoteDb1Connection = DriverManager::getConnection(['url' => 'mysql://user:pass@remote_host/remote_db1']);
        $this->localDb2Connection = DriverManager::getConnection(['url' => 'mysql://user:pass@localhost/local_db2']);
        $this->remoteDb2Connection = DriverManager::getConnection(['url' => 'mysql://user:pass@remote_host/remote_db2']);
    }

    public function testCompareDatabaseSchemas(): void
    {
        $errors = [];

        $this->compareSchemas($this->localDb1Connection, $this->remoteDb1Connection, 'Local DB1', 'Remote DB1', $errors);
        $this->compareSchemas($this->localDb2Connection, $this->remoteDb2Connection, 'Local DB2', 'Remote DB2', $errors);

        if (!empty($errors)) {
            $this->fail("Schema comparison errors:\n" . implode("\n", $errors));
        }

        $this->assertEmpty($errors, "Schema comparison passed without errors.");
    }

    private function compareSchemas($localConnection, $remoteConnection, string $localDbName, string $remoteDbName, array &$errors): void
    {
        $localSchemaManager = $localConnection->createSchemaManager();
        $remoteSchemaManager = $remoteConnection->createSchemaManager();

        $localTables = $localSchemaManager->listTableNames();
        $remoteTables = $remoteSchemaManager->listTableNames();

        foreach ($localTables as $localTableName) {
            if (str_ends_with($localTableName, '_pv')) {
                continue; // Ignoriere Tabellen, die auf '_pv' enden
            }

            if (!in_array($localTableName, $remoteTables)) {
                $errors[] = "Table '$localTableName' exists in $localDbName but not in $remoteDbName.";
                continue;
            }

            $localTable = $localSchemaManager->introspectTable($localTableName);
            $remoteTable = $remoteSchemaManager->introspectTable($localTableName);

            $localColumns = $localTable->getColumns();
            $remoteColumns = $remoteTable->getColumns();

            foreach ($localColumns as $localColumn) {
                $columnName = $localColumn->getName();
                if (!isset($remoteColumns[$columnName])) {
                    $errors[] = "Column '$columnName' in table '$localTableName' exists in $localDbName but not in $remoteDbName.";
                    continue;
                }

                $localType = get_class($localColumn->getType());
                $remoteType = get_class($remoteColumns[$columnName]->getType());

                if ($localType !== $remoteType) {
                    $errors[] = "Column type mismatch for '$columnName' in table '$localTableName' between $localDbName and $remoteDbName. Expected type: $localType, but got: $remoteType.";
                }
            }

            foreach ($remoteColumns as $remoteColumn) {
                $columnName = $remoteColumn->getName();
                if (!isset($localColumns[$columnName])) {
                    $errors[] = "Column '$columnName' in table '$localTableName' exists in $remoteDbName but not in $localDbName.";
                }
            }
        }

        foreach ($remoteTables as $remoteTableName) {
            if (!in_array($remoteTableName, $localTables)) {
                $errors[] = "Table '$remoteTableName' exists in $remoteDbName but not in $localDbName.";
            }
        }
    }
}
project-root/
├── src/
│ └── … (Hauptcode)
├── tests/
│ └── DatabaseSchemaTest.php
├── vendor/
│ └── … (Composer-Abhängigkeiten)
├── composer.json
└── phpunit.xml

PHPUnit-Konfiguration

Stellen Sie sicher, dass Sie eine phpunit.xml-Datei im Stammverzeichnis Ihres Projekts haben, die PHPUnit für das Ausführen der Tests konfiguriert. Eine einfache Konfiguration könnte so aussehen:

<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="vendor/autoload.php">
    <testsuites>
        <testsuite name="Application Test Suite">
            <directory>./tests</directory>
        </testsuite>
    </testsuites>
</phpunit>

Anpassen der bootstrap.php

Die Datei bootstrap.php im Ordner tests muss angepasst werden, damit der Autoloader für Composer-Pakete gefunden wird.

<?php

use Symfony\Component\Dotenv\Dotenv;

require dirname(__DIR__).'/vendor/autoload.php'; // Autoloader für Composer-Pakete

if (file_exists(dirname(__DIR__).'/config/bootstrap.php')) {
    require dirname(__DIR__).'/config/bootstrap.php';
} elseif (method_exists(Dotenv::class, 'bootEnv')) {
    (new Dotenv())->bootEnv(dirname(__DIR__).'/.env');
}

Manuelles Ausführen des Tests

Um den Test auszuführen, können Sie den folgenden Befehl im Terminal im Stammverzeichnis des Projekts verwenden:

vendor/bin/phpunit tests/DatabaseSchemaTest.php

Wie funktioniert das?

  1. SetUp-Methode: Die setUp()-Methode stellt Verbindungen zu den lokalen und entfernten Datenbanken her.
  2. Vergleich der Schemata: Die testCompareDatabaseSchemas()-Methode vergleicht die Tabellen und Spalten der lokalen und entfernten Datenbanken und sammelt alle Unterschiede.
  3. Fehlermeldungen: Am Ende des Tests wird überprüft, ob Fehler aufgetreten sind. Falls ja, werden alle Fehler ausgegeben, und der Test schlägt fehl.
  4. Integration in CI/CD: Diese Tests können in Ihre CI/CD-Pipeline integriert werden (siehe weiter unten). Wenn der Test fehlschlägt, wird der Deployment-Prozess gestoppt.

Hier ist eine kurze Erklärung der verschiedenen Zeichen, die PHPUnit verwendet:

  • “.” (Punkt): Ein Testfall wurde erfolgreich abgeschlossen.
  • “E” (Error): Ein Testfall hat einen Fehler verursacht, z.B. eine Ausnahme, die nicht abgefangen wurde.
  • “F” (Failure): Ein Testfall hat eine Assertion nicht bestanden.
  • “R” (Risky): Der Testfall wurde als riskant eingestuft, weil er z.B. keine Assertions enthält.
  • “S” (Skipped): Ein Testfall wurde übersprungen, z.B. aufgrund einer bestimmten Bedingung.
  • “I” (Incomplete): Ein Testfall ist unvollständig, z.B. weil er noch nicht vollständig implementiert ist.

Einbinden in Git push

Um sicherzustellen, dass ein git push nur dann ausgeführt wird, wenn der DatabaseSchemaTest erfolgreich durchläuft, sollte man einen Git-Hook verwenden. Git-Hooks sind Skripte, die Git automatisch bei bestimmten Ereignissen im Lebenszyklus eines Repositories ausführt. Der pre-push Hook wird unmittelbar vor dem Push-Vorgang ausgeführt und kann verwendet werden, um Tests zu starten und den Push-Vorgang bei einem Fehler zu verhindern.

Im Root-Verzeichnis des Git-Repositories gibt es einen versteckten Ordner .git/hooks. Erstellen Sie darin eine Datei namens pre-push (ohne Dateierweiterung), falls diese bisher nicht existiert.

touch .git/hooks/pre-push
chmod +x .git/hooks/pre-push

Öffnen Sie die pre-push Datei in einem Texteditor und fügen Sie folgendes Skript hinzu:

#!/bin/sh

# Führe PHPUnit Tests aus
./vendor/bin/phpunit --filter DatabaseSchemaTest

# Überprüfe den Exit-Code von PHPUnit
if [ $? -ne 0 ]; then
    echo "DatabaseSchemaTest failed. Push aborted."
    exit 1
fi

Dieses Skript führt den DatabaseSchemaTest aus. Wenn der Test fehlschlägt (d.h. PHPUnit gibt einen Exit-Code ungleich 0 zurück), wird der Push-Vorgang abgebrochen.

Ich habe hier mal einen Fehler simuliert bzw. absichtlich erzeugt.

Integrieren Sie diesen Test in Ihre CI/CD-Pipeline, um sicherzustellen, dass Sie nie wieder aufgrund von Datenbankunterschieden in der Produktion überrascht werden.