diff --git a/README.md b/README.md index decf734..a11d63c 100644 --- a/README.md +++ b/README.md @@ -7,29 +7,29 @@ Test- und Beispiel-Repository für einen lokalen Dev-Platform-Stack mit: - **Webhook-Trigger von Gitea nach Jenkins** - **C++/CMake/Ninja Build** - **PR Policy Checks** -- **Docker-basierter CI-Agent** +- **Docker-basiertem CI-Agent** --- -# Aktueller Funktionsumfang +## Aktueller Funktionsumfang Dieses Repository und das zugehörige Jenkins/Gitea-Setup können aktuell: -## SCM / Repository +### SCM / Repository - Repository in **Gitea** hosten - Änderungen per **Git Push** empfangen - **Pull Requests** in Gitea verwalten - Webhooks von Gitea an Jenkins senden -## Jenkins / CI +### Jenkins / CI - Jenkins als **Multibranch Pipeline** verwenden - Branches und Pull Requests automatisch erkennen - Builds durch **Push Events** automatisch starten - Build-Status an Gitea zurückmelden -## Build-Umgebung +### Build-Umgebung - Pipeline-Schritte in einem **Docker-Container** ausführen -- dafür ein vordefiniertes CI-Image verwenden +- dafür ein vorbereitetes CI-Image verwenden - folgende Tools im CI bereitstellen: - `python3` - `clang-format` @@ -39,27 +39,15 @@ Dieses Repository und das zugehörige Jenkins/Gitea-Setup können aktuell: - `g++` - `make` -## C++ Projektbasis +### C++ Projektbasis - minimales Beispielprogramm über `main.cpp` - Build mit **CMake** - Testausführung über **CTest** - Testdateien unter `tests/` -## PR Policy Checks -Für geänderte C/C++-Dateien werden in der CI geprüft: - -- `.clang-format` muss im Repository vorhanden sein -- geänderte C/C++-Dateien müssen mit `clang-format` konform sein -- zu geänderten C/C++-Dateien muss ein passender Test unter `tests/` oder `test/` vorhanden sein -- Vergleich gegen den Zielbranch erfolgt robust über Git-Refs wie z. B.: - - `origin/main` - - `main` - --- -# Repository-Struktur - -Beispielhaft verwendete Dateien: +## Repository-Struktur ```text . @@ -77,7 +65,7 @@ Beispielhaft verwendete Dateien: --- -# CI / Jenkins Pipeline +## CI / Jenkins Pipeline Die Jenkins-Pipeline umfasst aktuell diese Schritte: @@ -103,20 +91,39 @@ Die Jenkins-Pipeline umfasst aktuell diese Schritte: --- -# Docker-basierter CI-Agent +## PR Policy Checks + +Für geänderte C/C++-Dateien werden in der CI folgende Regeln geprüft: + +- `.clang-format` muss im Repository vorhanden sein +- geänderte C/C++-Dateien müssen mit `clang-format` konform sein +- zu geänderten C/C++-Dateien muss ein passender Test unter `tests/` oder `test/` vorhanden sein + +### Vergleichsbasis der Policy + +Die Policy unterscheidet zwischen Pull-Request-Builds und normalen Branch-Builds: + +- **bei Pull Requests** wird gegen den Zielbranch verglichen, z. B. `origin/main` +- **bei normalen Branch-Builds** wird auf eine lokale Vergleichsbasis zurückgefallen, z. B. `HEAD~1`, falls kein Zielbranch-Ref verfügbar ist + +Damit funktioniert die Policy sowohl in PR-Builds als auch bei regulären Branch-Indexing- oder Branch-Build-Läufen. + +--- + +## Docker-basierter CI-Agent Die Pipeline verwendet ein vorbereitetes Docker-Image statt bei jedem Lauf ein neues Build-Image zu erzeugen. -## Beispiel -Das Image wird lokal/auf dem Build-Host gebaut: +### Beispiel +Das Image wird lokal oder auf dem Build-Host gebaut: ```bash docker build -t lifemaps/ci-cpp:latest -f Dockerfile.ci . ``` -Danach nutzt Jenkins dieses Image als Agent. +Danach nutzt Jenkins dieses Image als Build-Agent. -## Vorteile +### Vorteile - schnellere PR-Builds - reproduzierbare Toolchain - keine langen `apt install`-Phasen pro Build @@ -124,7 +131,7 @@ Danach nutzt Jenkins dieses Image als Agent. --- -# Branch- und PR-Workflow +## Branch- und PR-Workflow Der aktuelle Workflow unterstützt: @@ -141,24 +148,24 @@ Empfohlen ist: --- -# Lokales Arbeiten +## Lokales Arbeiten -## Formatierung prüfen +### Formatierung prüfen ```bash clang-format --dry-run --Werror main.cpp tests/test_main.cpp ``` -## Formatierung anwenden +### Formatierung anwenden ```bash clang-format -i main.cpp tests/test_main.cpp ``` -## CI-Policy lokal testen +### CI-Policy lokal testen ```bash python3 ci/check_pr_policies.py ``` -## Build lokal ausführen +### Build lokal ausführen ```bash cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug cmake --build build --parallel @@ -167,7 +174,7 @@ ctest --test-dir build --output-on-failure --- -# Voraussetzungen auf Jenkins-Seite +## Voraussetzungen auf Jenkins-Seite Für das Setup werden u. a. folgende Jenkins-Plugins benötigt: @@ -189,7 +196,7 @@ Zusätzlich muss der Jenkins-Container Zugriff auf Docker haben, z. B. über: --- -# Webhook / Automatischer Trigger +## Webhook / Automatischer Trigger Gitea ist so konfiguriert, dass **Push Events** an Jenkins gemeldet werden. @@ -199,32 +206,26 @@ Beispiel-Endpunkt: https://jenkins.life-maps.com/gitea-webhook/post ``` -Damit können: -- neue Branch-Commits -- PR-bezogene Änderungen -- Status-Updates - -automatisch Jenkins-Builds auslösen. +Damit können automatisch Jenkins-Builds für Branches und Pull Requests ausgelöst werden. --- -# Beispielziel des Repositories +## Beispielziel des Repositories Dieses Repository dient aktuell als: - Referenz für Jenkins/Gitea-Integration - Testumgebung für PR-Policies - Minimalbeispiel für C++/CMake-basierte CI -- Grundlage für spätere Erweiterungen, z. B. mit Qt +- Grundlage für weitere CI- und Policy-Erweiterungen --- -# Status +## Status Aktuell ist das Setup geeignet für: - Jenkins/Gitea-Webhook-Integration - Pull-Request-basierte CI - C++/CMake/Ninja Beispielprojekte -- Policy-basierte Qualitätsprüfungen im PR-Prozess -- Vorbereitung auf weitergehende Qt-Migrations- und CI-Themen \ No newline at end of file +- Policy-basierte Qualitätsprüfungen im PR-Prozess \ No newline at end of file diff --git a/ci/check_pr_policies.py b/ci/check_pr_policies.py index fd87dcc..0e20a65 100644 --- a/ci/check_pr_policies.py +++ b/ci/check_pr_policies.py @@ -34,7 +34,10 @@ def git_ref_exists(ref: str) -> bool: except subprocess.CalledProcessError: return False -def resolve_target_ref() -> str: +def is_pull_request_build() -> bool: + return bool(os.environ.get("CHANGE_ID")) + +def resolve_target_ref() -> str | None: raw = os.environ.get("CHANGE_TARGET", "").strip() candidates = [] @@ -52,13 +55,27 @@ def resolve_target_ref() -> str: if git_ref_exists(ref): return ref - print("ERROR: Kein gültiger Ziel-Branch-Ref gefunden. Geprüft:", ", ".join(candidates)) - sys.exit(1) + return None def changed_files(): target = resolve_target_ref() - print(f"Vergleiche gegen Ziel-Ref: {target}") - out = run(f"git diff --name-only {target}...HEAD") + + if target: + print(f"Vergleiche gegen Ziel-Ref: {target}") + out = run(f"git diff --name-only {target}...HEAD") + return [line.strip() for line in out.splitlines() if line.strip()] + + if is_pull_request_build(): + print("ERROR: Kein gültiger Ziel-Branch-Ref für PR-Build gefunden.") + sys.exit(1) + + if git_ref_exists("HEAD~1"): + print("Kein Ziel-Branch-Ref gefunden, verwende HEAD~1 für Branch-Build.") + out = run("git diff --name-only HEAD~1..HEAD") + return [line.strip() for line in out.splitlines() if line.strip()] + + print("Keine Vergleichsbasis gefunden, behandle alle versionierten Dateien als geändert.") + out = run("git ls-files") return [line.strip() for line in out.splitlines() if line.strip()] def is_cpp_file(path: Path) -> bool: diff --git a/hook-test.txt b/hook-test.txt deleted file mode 100644 index 044762d..0000000 --- a/hook-test.txt +++ /dev/null @@ -1 +0,0 @@ -hook test Di 4. Aug 00:08:29 CEST 2026 diff --git a/protected-main-test.txt b/protected-main-test.txt deleted file mode 100644 index 1157fae..0000000 --- a/protected-main-test.txt +++ /dev/null @@ -1 +0,0 @@ -should fail diff --git a/push-hook-test.txt b/push-hook-test.txt deleted file mode 100644 index f2d2344..0000000 --- a/push-hook-test.txt +++ /dev/null @@ -1 +0,0 @@ -push-hook-test Di 4. Aug 00:11:58 CEST 2026